Merge lp:~michihenning/unity-scopes-api/cache-results into lp:unity-scopes-api

Proposed by Michi Henning
Status: Superseded
Proposed branch: lp:~michihenning/unity-scopes-api/cache-results
Merge into: lp:unity-scopes-api
Diff against target: 5555 lines (+1999/-631)
123 files modified
CMakeLists.txt (+0/-6)
CONFIGFILES (+38/-2)
HACKING (+0/-27)
debian/libunity-scopes3.symbols (+11/-3)
doc/Doxyfile-devel.in (+1/-1)
doc/tutorial.dox (+13/-0)
include/unity/scopes/CategorisedResult.h (+2/-0)
include/unity/scopes/Category.h (+2/-0)
include/unity/scopes/SearchReply.h (+21/-0)
include/unity/scopes/internal/' (+59/-0)
include/unity/scopes/internal/ActivationQueryObject.h (+1/-2)
include/unity/scopes/internal/CategoryRegistry.h (+13/-4)
include/unity/scopes/internal/DfltConfig.h.in (+14/-6)
include/unity/scopes/internal/Logger.h (+55/-9)
include/unity/scopes/internal/ObjectImpl.h (+1/-4)
include/unity/scopes/internal/PreviewQueryObject.h (+1/-2)
include/unity/scopes/internal/PreviewReplyImpl.h (+1/-2)
include/unity/scopes/internal/QueryCtrlImpl.h (+1/-3)
include/unity/scopes/internal/QueryCtrlObjectBase.h (+2/-1)
include/unity/scopes/internal/QueryObject.h (+2/-6)
include/unity/scopes/internal/QueryObjectBase.h (+2/-1)
include/unity/scopes/internal/RegistryImpl.h (+1/-3)
include/unity/scopes/internal/ReplyImpl.h (+1/-3)
include/unity/scopes/internal/ReplyObject.h (+1/-0)
include/unity/scopes/internal/RuntimeConfig.h (+10/-0)
include/unity/scopes/internal/RuntimeImpl.h (+4/-1)
include/unity/scopes/internal/ScopeImpl.h (+2/-2)
include/unity/scopes/internal/ScopeObject.h (+1/-3)
include/unity/scopes/internal/ScopeObjectBase.h (+2/-1)
include/unity/scopes/internal/SearchReplyImpl.h (+13/-2)
include/unity/scopes/internal/smartscopes/SSQueryObject.h (+1/-3)
include/unity/scopes/internal/smartscopes/SSScopeObject.h (+0/-2)
include/unity/scopes/internal/smartscopes/SmartScopesClient.h (+5/-2)
include/unity/scopes/internal/zmq_middleware/ObjectAdapter.h (+7/-2)
include/unity/scopes/internal/zmq_middleware/ZmqException.h (+4/-1)
include/unity/scopes/internal/zmq_middleware/ZmqObjectProxy.h (+10/-4)
include/unity/scopes/testing/MockSearchReply.h (+1/-0)
include/unity/scopes/utility/internal/BufferedSearchReplyImpl.h (+6/-3)
scoperegistry/DirWatcher.cpp (+9/-7)
scoperegistry/ScopesWatcher.cpp (+4/-4)
scoperegistry/scoperegistry.cpp (+1/-1)
src/scopes/internal/ActivationQueryObject.cpp (+9/-8)
src/scopes/internal/CategoryRegistry.cpp (+19/-6)
src/scopes/internal/JsonCppNode.cpp (+1/-1)
src/scopes/internal/Logger.cpp (+143/-49)
src/scopes/internal/ObjectImpl.cpp (+1/-3)
src/scopes/internal/PreviewQueryObject.cpp (+9/-8)
src/scopes/internal/PreviewReplyImpl.cpp (+3/-5)
src/scopes/internal/QueryCtrlImpl.cpp (+3/-4)
src/scopes/internal/QueryObject.cpp (+13/-11)
src/scopes/internal/RegistryImpl.cpp (+2/-2)
src/scopes/internal/RegistryObject.cpp (+15/-21)
src/scopes/internal/ReplyImpl.cpp (+8/-8)
src/scopes/internal/ReplyObject.cpp (+4/-4)
src/scopes/internal/ResultReplyObject.cpp (+2/-1)
src/scopes/internal/RuntimeConfig.cpp (+125/-18)
src/scopes/internal/RuntimeImpl.cpp (+47/-9)
src/scopes/internal/ScopeImpl.cpp (+10/-10)
src/scopes/internal/ScopeMetadataImpl.cpp (+1/-1)
src/scopes/internal/ScopeObject.cpp (+12/-16)
src/scopes/internal/SearchReplyImpl.cpp (+234/-17)
src/scopes/internal/SettingsDB.cpp (+10/-7)
src/scopes/internal/smartscopes/SSQueryObject.cpp (+9/-8)
src/scopes/internal/smartscopes/SSRegistryObject.cpp (+7/-9)
src/scopes/internal/smartscopes/SSScopeObject.cpp (+3/-4)
src/scopes/internal/smartscopes/SmartScope.cpp (+6/-5)
src/scopes/internal/smartscopes/SmartScopesClient.cpp (+32/-33)
src/scopes/internal/zmq_middleware/ObjectAdapter.cpp (+45/-12)
src/scopes/internal/zmq_middleware/ZmqException.cpp (+52/-3)
src/scopes/internal/zmq_middleware/ZmqMiddleware.cpp (+14/-14)
src/scopes/internal/zmq_middleware/ZmqObject.cpp (+47/-44)
src/scopes/internal/zmq_middleware/ZmqRegistry.cpp (+1/-1)
src/scopes/internal/zmq_middleware/ZmqScope.cpp (+4/-5)
src/scopes/testing/InProcessBenchmark.cpp (+4/-0)
src/scopes/utility/internal/BufferedResultForwarderImpl.cpp (+1/-1)
src/scopes/utility/internal/BufferedSearchReplyImpl.cpp (+5/-0)
test/gtest/scopes/Activation/Activation_test.cpp (+1/-1)
test/gtest/scopes/Activation/Runtime.ini.in (+1/-0)
test/gtest/scopes/CMakeLists.txt (+1/-0)
test/gtest/scopes/Filters/Filters_test.cpp (+1/-1)
test/gtest/scopes/Filters/Runtime.ini.in (+1/-0)
test/gtest/scopes/IdleShutdown/IdleShutdown_test.cpp (+1/-1)
test/gtest/scopes/IdleShutdown/Runtime.ini.in (+1/-0)
test/gtest/scopes/Invocation/Invocation_test.cpp (+3/-3)
test/gtest/scopes/Invocation/Runtime.ini.in (+1/-0)
test/gtest/scopes/Registry/Runtime.ini.in (+1/-0)
test/gtest/scopes/ReplyReaper/ReplyReaper_test.cpp (+2/-2)
test/gtest/scopes/ReplyReaper/Runtime.ini.in (+1/-0)
test/gtest/scopes/ResultCache/CMakeLists.txt (+27/-0)
test/gtest/scopes/ResultCache/CacheScope.cpp (+146/-0)
test/gtest/scopes/ResultCache/CacheScope.h (+41/-0)
test/gtest/scopes/ResultCache/CacheScope.ini.in (+4/-0)
test/gtest/scopes/ResultCache/ResultCache_test.cpp (+343/-0)
test/gtest/scopes/ResultCache/Runtime.ini.in (+8/-0)
test/gtest/scopes/ResultCache/TestRegistry.ini.in (+7/-0)
test/gtest/scopes/ResultCache/Zmq.ini.in (+2/-0)
test/gtest/scopes/ResultCache/no_cat_cache (+1/-0)
test/gtest/scopes/ResultCache/no_dept_cache (+1/-0)
test/gtest/scopes/ResultCache/no_results_cache (+1/-0)
test/gtest/scopes/Runtime/Runtime.ini.in (+1/-0)
test/gtest/scopes/Runtime/Runtime_test.cpp (+5/-5)
test/gtest/scopes/internal/ResultReplyObject/Runtime.ini.in (+1/-0)
test/gtest/scopes/internal/RuntimeConfig/BadLogDirSize.ini (+7/-0)
test/gtest/scopes/internal/RuntimeConfig/BadLogFileSize.ini (+6/-0)
test/gtest/scopes/internal/RuntimeConfig/CacheDir.ini (+1/-0)
test/gtest/scopes/internal/RuntimeConfig/Complete.ini (+16/-0)
test/gtest/scopes/internal/RuntimeConfig/ConfigDir.ini (+1/-0)
test/gtest/scopes/internal/RuntimeConfig/LogDir.ini (+5/-0)
test/gtest/scopes/internal/RuntimeConfig/NoLogDir.ini (+4/-0)
test/gtest/scopes/internal/RuntimeConfig/RuntimeConfig_test.cpp (+114/-2)
test/gtest/scopes/internal/RuntimeImpl/Runtime.ini.in (+1/-0)
test/gtest/scopes/internal/ScopeMetadataImpl/Runtime.ini.in (+1/-0)
test/gtest/scopes/internal/ScopeMetadataImpl/ScopeMetadataImpl_test.cpp (+4/-4)
test/gtest/scopes/internal/SettingsDB/SettingsDB_test.cpp (+2/-2)
test/gtest/scopes/internal/smartscopes/SmartScopesClient/SmartScopesClient_test.cpp (+2/-5)
test/gtest/scopes/internal/smartscopes/smartscopesproxy/Runtime.ini.in (+1/-0)
test/gtest/scopes/internal/zmq_middleware/ObjectAdapter/Runtime.ini.in (+1/-0)
test/gtest/scopes/internal/zmq_middleware/RegistryI/RegistryI_test.cpp (+3/-3)
test/gtest/scopes/internal/zmq_middleware/RegistryI/Runtime.ini.in (+1/-0)
test/gtest/scopes/internal/zmq_middleware/ZmqMiddleware/Runtime.ini.in (+1/-0)
test/gtest/scopes/stress/Runtime.ini.in (+1/-0)
tools/zmq-monitor-host.py (+0/-46)
tools/zmq-parser.py (+0/-85)
To merge this branch: bzr merge lp:~michihenning/unity-scopes-api/cache-results
Reviewer Review Type Date Requested Status
Unity Team Pending
Review via email: mp+246256@code.launchpad.net

This proposal has been superseded by a proposal from 2015-01-13.

Commit message

Added result cache that stores the results of the last successful surfacing query. The scope, if it detects connectivity problems, can call reply->push_surfacing_results_from_cache(). This answers the query from the cache, provided that the query is indeed a surfacing query. Otherwise, the method does nothing.

Description of the change

Added result cache that stores the results of the last successful surfacing query. The scope, if it detects connectivity problems, can call reply->push_surfacing_results_from_cache(). This answers the query from the cache, provided that the query is indeed a surfacing query. Otherwise, the method does nothing.

Note: I have not yet updated RELEASE_NOTES, changelog, and minor version number. Still waiting on a decision about ABI breaks. Once that is sorted out, I'll push changes accordingly. For now, I want to see what Jenkins has to say.

To post a comment you must log in.
573. By Michi Henning

Bumped micro version and updated release notes and changelog.

574. By Michi Henning

Merged dependent branch.

575. By Michi Henning

Fixed RuntimeConfig test again because it failed under bzr bd.

576. By Michi Henning

Merged trunk and resolved conflicts.

577. By Michi Henning

Merged trunk.

578. By Michi Henning

Simplified CategorisedResult instantiation when pushing from cache.

579. By Michi Henning

Added filters and filter_state to cached results and added corresponding tests.

580. By Michi Henning

Moved push_surfacing_results_from_cache to end of virtual functions to
avoid ABI break.

581. By Michi Henning

Merged trunk and resolved conflicts.

582. By Michi Henning

Update micro version, changelog, and release notes.

583. By Michi Henning

Fixed changelog. (Thanks Pawel!)

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2014-12-09 15:26:12 +0000
3+++ CMakeLists.txt 2015-01-13 07:11:02 +0000
4@@ -193,12 +193,6 @@
5 message(FATAL_ERROR "Invalid SANITIZER setting: ${SANITIZER}")
6 endif()
7
8-option(IPC_MONITORING "Enable IPC traffic monitoring")
9-
10-if(IPC_MONITORING)
11- add_definitions(-DENABLE_IPC_MONITOR)
12-endif()
13-
14 # Scopes library name. Also used as a prefix in various places, and as a subdirectory
15 # name for installed files. Changing this will also require corresponding changes
16 # to the debian files.
17
18=== modified file 'CONFIGFILES'
19--- CONFIGFILES 2014-12-03 08:05:20 +0000
20+++ CONFIGFILES 2015-01-13 07:11:02 +0000
21@@ -123,7 +123,15 @@
22
23 - ConfigDir
24
25- The parent directory under which the runtime writes the scope configration files.
26+ The parent directory under which the run time writes the scope configration files.
27+
28+ The default value is $HOME/.cache/unity-scopes.
29+
30+- LogDir
31+
32+ The parent directory under which the run time writes the scope configration files.
33+ Setting this value explicitly to the empty string disables file logging and forces
34+ all log entries to go to stderr.
35
36 The default value is $HOME/.config/unity-scopes.
37
38@@ -132,6 +140,34 @@
39
40 $HOME/.config/unity-scopes/<scope_id>/settings.ini
41
42+ The environment variable UNITY_SCOPES_LOGDIR overrides this key.
43+ Setting this variable explicitly to the empty string disables file logging and forces
44+ all log entries to go to stderr.
45+
46+- Log.MaxFileSize
47+
48+ The maximum size in bytes of an individual log file before it is rolled over.
49+ The value must be at least 1024. The default value is 512 kB.
50+
51+- Log.MaxDirSize
52+
53+ The maximum size in bytes of the sum of sizes of all log files in the log directory
54+ before they are deleted. The value must be greater than Log.MaxFileSize.
55+ The default value is 10 MB.
56+
57+- Log.TraceChannels
58+
59+ The names of channels for which to emit trace. This must be a semicolon-separated
60+ list of channel names. By default, tracing for all channels is disabled.
61+ Valid channel names are:
62+
63+ - IPC
64+
65+ Trace inter-process messages activity.
66+
67+ The environment variable UNITY_SCOPES_LOG_TRACECHANNELS overrides this key.
68+ The value must be a semicolon-separate list of channel names.
69+
70
71 Zmq.ini
72 -------
73@@ -371,7 +407,7 @@
74 A custom scoperunner command-line to be executed when the scope is invoked.
75 The following placeholders can be used to substitute config paths where required:
76
77- - %R - absolute path to the runtime .ini config file
78+ - %R - absolute path to the run time .ini config file
79 - %S - absolute path to the scope's .ini config file
80
81 E.g. "ScopeRunner = /usr/bin/gdb --ex run --args /usr/lib/x86_64-linux-gnu/unity-scopes/scoperunner %R %S"
82
83=== modified file 'HACKING'
84--- HACKING 2014-10-09 02:52:15 +0000
85+++ HACKING 2015-01-13 07:11:02 +0000
86@@ -190,33 +190,6 @@
87
88 The report provides a nicely layed-out page with all the details.
89
90-Debugging IPC
91--------------
92-
93-There are lots of messages being passed between the various scope processes,
94-and therefore it might be sometimes useful to see those to help with debugging.
95-There is a special monitoring code that is enabled if you pass
96--DIPC_MONITORING=ON to cmake. When you build the library with this code,
97-the messages can be introspected using the python scripts in the tools directory.
98-
99-Note that the tools require python dependencies that are otherwise not required
100-for regular builds, to get those, grab python-zmq and python-capnproto.
101-
102-As of time of writing this, python-capnproto is not present in the distro,
103-so get it from https://github.com/jparyani/pycapnp.git, also note that the master
104-branch is compatible with capnproto 0.3, not 0.4 which we're using, so you need
105-to switch to the "feature/v0.4" branch.
106-
107-Once you have the extra python dependencies you need to run:
108-
109- $ ./zmq-monitor-host.py &
110-
111-This runs a monitor proxy that forwards the monitored messages from all publishers
112-to all subscribers.
113-Then you can run a subscriber that will display content of the messages:
114-
115- $ ./zmq-parser.py
116-
117 Autopkg test suite
118 ------------------
119
120
121=== modified file 'debian/libunity-scopes3.symbols'
122--- debian/libunity-scopes3.symbols 2014-12-10 12:59:46 +0000
123+++ debian/libunity-scopes3.symbols 2015-01-13 07:11:02 +0000
124@@ -403,8 +403,12 @@
125 (c++)"unity::scopes::internal::RuntimeConfig::default_app_directory()@Base" 0.6.9+15.04.20141129
126 (c++)"unity::scopes::internal::RuntimeConfig::default_cache_directory()@Base" 0.6.9+15.04.20141129
127 (c++)"unity::scopes::internal::RuntimeConfig::default_config_directory()@Base" 0.6.2+rtm+rtm+rtm+14.09.20140818
128+ (c++)"unity::scopes::internal::RuntimeConfig::default_log_directory()@Base" 0replaceme
129 (c++)"unity::scopes::internal::RuntimeConfig::default_middleware_configfile() const@Base" 0.4.2+14.04.20140404.2
130 (c++)"unity::scopes::internal::RuntimeConfig::default_middleware() const@Base" 0.4.2+14.04.20140404.2
131+ (c++)"unity::scopes::internal::RuntimeConfig::log_directory() const@Base" 0replaceme
132+ (c++)"unity::scopes::internal::RuntimeConfig::max_log_dir_size() const@Base" 0replaceme
133+ (c++)"unity::scopes::internal::RuntimeConfig::max_log_file_size() const@Base" 0replaceme
134 (c++)"unity::scopes::internal::RuntimeConfig::reap_expiry() const@Base" 0.4.5+14.10.20140513
135 (c++)"unity::scopes::internal::RuntimeConfig::reap_interval() const@Base" 0.4.5+14.10.20140513
136 (c++)"unity::scopes::internal::RuntimeConfig::registry_configfile() const@Base" 0.4.2+14.04.20140404.2
137@@ -413,7 +417,9 @@
138 (c++)"unity::scopes::internal::RuntimeConfig::RuntimeConfig(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.4.2+14.04.20140404.2
139 (c++)"unity::scopes::internal::RuntimeConfig::ss_configfile() const@Base" 0.4.4+14.10.20140508
140 (c++)"unity::scopes::internal::RuntimeConfig::ss_registry_identity() const@Base" 0.4.4+14.10.20140508
141+ (c++)"unity::scopes::internal::RuntimeConfig::trace_channels() const@Base" 0replaceme
142 (c++)"unity::scopes::internal::RuntimeImpl::async_pool() const@Base" 0.4.3+14.10.20140428
143+ (c++)"unity::scopes::internal::RuntimeImpl::cache_directory() const@Base" 0replaceme
144 (c++)"unity::scopes::internal::RuntimeImpl::confined() const@Base" 0.6.8+15.04.20141119
145 (c++)"unity::scopes::internal::RuntimeImpl::confinement_type() const@Base" 0.6.8+15.04.20141119
146 (c++)"unity::scopes::internal::RuntimeImpl::create(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.4.0+14.04.20140312.1
147@@ -425,6 +431,7 @@
148 (c++)"unity::scopes::internal::RuntimeImpl::find_tmp_dir() const@Base" 0.6.8+15.04.20141119
149 (c++)"unity::scopes::internal::RuntimeImpl::future_queue() const@Base" 0.4.3+14.10.20140428
150 (c++)"unity::scopes::internal::RuntimeImpl::logger() const@Base" 0.6.10+15.04.20141210.2
151+ (c++)"unity::scopes::internal::RuntimeImpl::logger(unity::scopes::internal::Logger::Channel) const@Base" 0replaceme
152 (c++)"unity::scopes::internal::RuntimeImpl::proxy_to_string(std::shared_ptr<unity::scopes::Object> const&) const@Base" 0.4.0+14.04.20140312.1
153 (c++)"unity::scopes::internal::RuntimeImpl::registry_configfile() const@Base" 0.4.0+14.04.20140312.1
154 (c++)"unity::scopes::internal::RuntimeImpl::registry() const@Base" 0.4.0+14.04.20140312.1
155@@ -437,6 +444,7 @@
156 (c++)"unity::scopes::internal::RuntimeImpl::ss_configfile() const@Base" 0.4.4+14.10.20140508
157 (c++)"unity::scopes::internal::RuntimeImpl::ss_registry_identity() const@Base" 0.4.4+14.10.20140508
158 (c++)"unity::scopes::internal::RuntimeImpl::string_to_proxy(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const@Base" 0.4.0+14.04.20140312.1
159+ (c++)"unity::scopes::internal::RuntimeImpl::tmp_directory() const@Base" 0replaceme
160 (c++)"unity::scopes::internal::RuntimeImpl::waiter_thread(std::shared_ptr<unity::scopes::internal::ThreadSafeQueue<std::future<void> > > const&) const@Base" 0.4.3+14.10.20140428
161 (c++)"unity::scopes::internal::safe_strerror(int)@Base" 0.6.9+15.04.20141129
162 (c++)"unity::scopes::internal::ScopeConfig::appearance_attributes() const@Base" 0.4.2+14.04.20140404.2
163@@ -462,12 +470,12 @@
164 (c++)"unity::scopes::internal::ScopeConfig::search_hint() const@Base" 0.4.0+14.04.20140312.1
165 (c++)"unity::scopes::internal::ScopeConfig::version() const@Base" 0.6.9+15.04.20141129
166 (c++)"unity::scopes::internal::ScopeImpl::activate(unity::scopes::Result const&, unity::scopes::ActionMetadata const&, std::shared_ptr<unity::scopes::ActivationListenerBase> const&)@Base" 0.4.0+14.04.20140312.1
167- (c++)"unity::scopes::internal::ScopeImpl::create(std::shared_ptr<unity::scopes::internal::MWScope> const&, unity::scopes::internal::RuntimeImpl*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.4.0+14.04.20140312.1
168+ (c++)"unity::scopes::internal::ScopeImpl::create(std::shared_ptr<unity::scopes::internal::MWScope> const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0replaceme
169 (c++)"unity::scopes::internal::ScopeImpl::fwd()@Base" 0.4.3+14.10.20140428
170 (c++)"unity::scopes::internal::ScopeImpl::perform_action(unity::scopes::Result const&, unity::scopes::ActionMetadata const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::shared_ptr<unity::scopes::ActivationListenerBase> const&)@Base" 0.4.0+14.04.20140312.1
171 (c++)"unity::scopes::internal::ScopeImpl::preview(unity::scopes::Result const&, unity::scopes::ActionMetadata const&, std::shared_ptr<unity::scopes::PreviewListenerBase> const&)@Base" 0.4.0+14.04.20140312.1
172 (c++)"unity::scopes::internal::ScopeImpl::~ScopeImpl()@Base" 0.4.0+14.04.20140312.1
173- (c++)"unity::scopes::internal::ScopeImpl::ScopeImpl(std::shared_ptr<unity::scopes::internal::MWScope> const&, unity::scopes::internal::RuntimeImpl*, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0.4.0+14.04.20140312.1
174+ (c++)"unity::scopes::internal::ScopeImpl::ScopeImpl(std::shared_ptr<unity::scopes::internal::MWScope> const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)@Base" 0replaceme
175 (c++)"unity::scopes::internal::ScopeImpl::search(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unity::scopes::FilterState const&, unity::scopes::SearchMetadata const&, std::shared_ptr<unity::scopes::SearchListenerBase> const&)@Base" 0.4.0+14.04.20140312.1
176 (c++)"unity::scopes::internal::ScopeImpl::search(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unity::scopes::FilterState const&, unity::scopes::SearchMetadata const&, std::shared_ptr<unity::scopes::SearchListenerBase> const&)@Base" 0.4.0+14.04.20140312.1
177 (c++)"unity::scopes::internal::ScopeImpl::search(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, unity::scopes::SearchMetadata const&, std::shared_ptr<unity::scopes::SearchListenerBase> const&)@Base" 0.4.0+14.04.20140312.1
178@@ -532,7 +540,7 @@
179 (c++)"unity::scopes::internal::ScopeObject::preview(unity::scopes::Result const&, unity::scopes::ActionMetadata const&, std::shared_ptr<unity::scopes::internal::MWReply> const&, unity::scopes::internal::InvokeInfo const&)@Base" 0.4.0+14.04.20140312.1
180 (c++)"unity::scopes::internal::ScopeObject::query(std::shared_ptr<unity::scopes::internal::MWReply> const&, unity::scopes::internal::MiddlewareBase*, std::function<std::shared_ptr<unity::scopes::QueryBase> ()> const&, std::function<std::shared_ptr<unity::scopes::internal::QueryObjectBase> (std::shared_ptr<unity::scopes::QueryBase>, std::shared_ptr<unity::scopes::internal::MWQueryCtrl>)> const&)@Base" 0.4.0+14.04.20140312.1
181 (c++)"unity::scopes::internal::ScopeObject::~ScopeObject()@Base" 0.4.0+14.04.20140312.1
182- (c++)"unity::scopes::internal::ScopeObject::ScopeObject(unity::scopes::internal::RuntimeImpl*, unity::scopes::ScopeBase*, bool)@Base" 0.6.2+rtm+rtm+rtm+14.09.20140818
183+ (c++)"unity::scopes::internal::ScopeObject::ScopeObject(unity::scopes::ScopeBase*, bool)@Base" 0replaceme
184 (c++)"unity::scopes::internal::ScopeObject::search(unity::scopes::CannedQuery const&, unity::scopes::SearchMetadata const&, std::shared_ptr<unity::scopes::internal::MWReply> const&, unity::scopes::internal::InvokeInfo const&)@Base" 0.4.0+14.04.20140312.1
185 (c++)"unity::scopes::internal::smartscopes::SSConfig::http_reply_timeout() const@Base" 0.4.4+14.10.20140508
186 (c++)"unity::scopes::internal::smartscopes::SSConfig::reg_refresh_fail_timeout() const@Base" 0.4.4+14.10.20140508
187
188=== modified file 'doc/Doxyfile-devel.in'
189--- doc/Doxyfile-devel.in 2014-06-16 03:26:21 +0000
190+++ doc/Doxyfile-devel.in 2015-01-13 07:11:02 +0000
191@@ -1758,7 +1758,7 @@
192 # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
193 # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
194
195-DOT_GRAPH_MAX_NODES = 50
196+DOT_GRAPH_MAX_NODES = 100
197
198 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
199 # graphs generated by dot. A depth value of 3 means that only nodes reachable
200
201=== modified file 'doc/tutorial.dox'
202--- doc/tutorial.dox 2014-12-10 10:15:55 +0000
203+++ doc/tutorial.dox 2015-01-13 07:11:02 +0000
204@@ -229,6 +229,19 @@
205 here (if at all possible), so the user gets to see at least some results (instead of being confronted with
206 a blank screen).
207
208+The runtime automatically saves the results of the most recent surfacing query. If a scope cannot produce
209+a result for a surfacing query (presumably, due to connectivity problems), calling
210+\link unity::scopes::SearchReply::push_surfacing_results_from_cache() push_surfacing_results_from_cache()\endlink
211+pushes the results that were produced by the most recent successful
212+surfacing query from the cache. If your scope cannot produce surfacing results, you can call this
213+method to "replay" the results of the previous surfacing query. In turn, this avoids the user
214+being presented with an empty screen if he/she swipes to the scope while the device does not have connectivity.
215+
216+`push_surfacing_results_from_cache()` has an effect only if called for a surfacing query (that is, a query with an empty query string). If called for a non-empty query, it does nothing.
217+
218+You must call this method before calling \link unity::scopes::Reply::finished finished()\endlink,
219+otherwise no cached results will be pushed. (`push_surfacing_results_from_cache() implicitly calls `finished()`);
220+
221 \paragraph querybase Implementing QueryBase
222
223 You must implement a class that derives from \link unity::scopes::SearchQueryBase SearchQueryBase\endlink and return
224
225=== modified file 'include/unity/scopes/CategorisedResult.h'
226--- include/unity/scopes/CategorisedResult.h 2014-11-03 05:31:30 +0000
227+++ include/unity/scopes/CategorisedResult.h 2015-01-13 07:11:02 +0000
228@@ -31,6 +31,7 @@
229 {
230 class CategorisedResultImpl;
231 class ResultReplyObject;
232+ class SearchReplyImpl;
233 }
234
235 /**
236@@ -80,6 +81,7 @@
237
238 friend class internal::CategorisedResultImpl;
239 friend class internal::ResultReplyObject;
240+ friend class internal::SearchReplyImpl;
241 };
242
243 } // namespace scopes
244
245=== modified file 'include/unity/scopes/Category.h'
246--- include/unity/scopes/Category.h 2014-11-03 05:31:30 +0000
247+++ include/unity/scopes/Category.h 2015-01-13 07:11:02 +0000
248@@ -36,6 +36,7 @@
249 {
250 class CategoryImpl;
251 class CategoryRegistry;
252+ class SearchReplyImpl;
253 }
254
255 /**
256@@ -100,6 +101,7 @@
257 /// @endcond
258
259 friend class internal::CategoryRegistry;
260+ friend class internal::SearchReplyImpl;
261
262 private:
263 std::unique_ptr<internal::CategoryImpl> p;
264
265=== modified file 'include/unity/scopes/SearchReply.h'
266--- include/unity/scopes/SearchReply.h 2014-11-03 05:31:30 +0000
267+++ include/unity/scopes/SearchReply.h 2015-01-13 07:11:02 +0000
268@@ -141,6 +141,27 @@
269 virtual bool push(Filters const& filters, FilterState const& filter_state) = 0;
270
271 /**
272+ \brief Push the results that were produced by the most recent surfacing query.
273+
274+ The runtime automatically saves the results of the most recent surfacing query.
275+ If a scope cannot produce a result for a surfacing query (presumably, due to
276+ connectivity problems), calling push_surfacing_results_from_cache() pushes
277+ the results that were produced by the most recent successful surfacing query
278+ from the cache. If a scope cannot produce surfacing results, it can call this
279+ method to "replay" the previous results. In turn, this avoids the user being
280+ presented with an empty screen if he/she swipes to the scope while the device
281+ does not have connectivity.
282+
283+ This method has an effect only if called for a surfacing query (that is, a
284+ query with an empty query string). If called for a non-empty query, it does
285+ nothing.
286+
287+ You must call this method before calling finished(), otherwise no cached results
288+ will be pushed (push_surfacing_results_from_cache() implicitly calls finished()).
289+ */
290+ virtual void push_surfacing_results_from_cache() = 0;
291+
292+ /**
293 \brief Destroys a Reply.
294
295 If a Reply goes out of scope without a prior call to finished(), the destructor implicitly calls finished().
296
297=== added file 'include/unity/scopes/internal/''
298--- include/unity/scopes/internal/' 1970-01-01 00:00:00 +0000
299+++ include/unity/scopes/internal/' 2015-01-13 07:11:02 +0000
300@@ -0,0 +1,59 @@
301+/*
302+ * Copyright (C) 2013 Canonical Ltd
303+ *
304+ * This program is free software: you can redistribute it and/or modify
305+ * it under the terms of the GNU Lesser General Public License version 3 as
306+ * published by the Free Software Foundation.
307+ *
308+ * This program is distributed in the hope that it will be useful,
309+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
310+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
311+ * GNU Lesser General Public License for more details.
312+ *
313+ * You should have received a copy of the GNU Lesser General Public License
314+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
315+ *
316+ * Authored by: Michi Henning <michi.henning@canonical.com>
317+ */
318+
319+#pragma once
320+
321+#include <unity/scopes/internal/MWRegistryProxyFwd.h>
322+#include <unity/scopes/internal/ObjectImpl.h>
323+#include <unity/scopes/Registry.h>
324+
325+namespace unity
326+{
327+
328+namespace scopes
329+{
330+
331+namespace internal
332+{
333+
334+class RegistryImpl : public virtual unity::scopes::Registry, public virtual ObjectImpl
335+{
336+public:
337+ RegistryImpl(MWRegistryProxy const& mw_proxy);
338+ ~RegistryImpl();
339+
340+ virtual ScopeMetadata get_metadata(std::string const& scope_id) override;
341+ virtual MetadataMap list() override;
342+ virtual MetadataMap list_if(std::function<bool(ScopeMetadata const& item)> predicate) override;
343+ virtual bool is_scope_running(std::string const& scope_id) override;
344+
345+ virtual core::ScopedConnection set_scope_state_callback(std::string const& scope_id, std::function<void(bool)> callback) override;
346+ virtual core::ScopedConnection set_list_update_callback(std::function<void()> callback) override;
347+
348+ // Remote operation. Not part of public API, hence not override.
349+ ObjectProxy locate(std::string const& identity);
350+
351+private:
352+ MWRegistryProxy fwd();
353+};
354+
355+} // namespace internal
356+
357+} // namespace scopes
358+
359+} // namespace unity
360
361=== modified file 'include/unity/scopes/internal/ActivationQueryObject.h'
362--- include/unity/scopes/internal/ActivationQueryObject.h 2014-11-20 05:32:53 +0000
363+++ include/unity/scopes/internal/ActivationQueryObject.h 2015-01-13 07:11:02 +0000
364@@ -38,8 +38,7 @@
365
366 ActivationQueryObject(std::shared_ptr<ActivationQueryBase> const& act_base,
367 MWReplyProxy const& reply,
368- MWQueryCtrlProxy const& ctrl,
369- boost::log::sources::severity_channel_logger_mt<>& logger);
370+ MWQueryCtrlProxy const& ctrl);
371 virtual ~ActivationQueryObject();
372 virtual void run(MWReplyProxy const& reply, InvokeInfo const& info) noexcept override;
373
374
375=== modified file 'include/unity/scopes/internal/CategoryRegistry.h'
376--- include/unity/scopes/internal/CategoryRegistry.h 2014-11-03 05:31:30 +0000
377+++ include/unity/scopes/internal/CategoryRegistry.h 2015-01-13 07:11:02 +0000
378@@ -46,13 +46,15 @@
379 CategoryRegistry() = default;
380
381 /**
382- \brief Deserializes category from a variant_map and registers it. Throws if category with same id exists.
383+ \brief Deserializes category from a variant_map and registers it.
384+ \throws unity::InvalidArgumentException if a category with the same id exists already.
385 \return category instance
386 */
387 Category::SCPtr register_category(VariantMap const& variant_map);
388
389 /**
390- \brief Creates category from supplied parameters. Throws if category with same id exists.
391+ \brief Creates category from supplied parameters.
392+ \throws unity::InvalidArgumentException if a category with the same id exists already.
393 \return category instance
394 */
395 Category::SCPtr register_category(std::string const& id, std::string const& title, std::string const& icon, CannedQuery::SCPtr const& query, CategoryRenderer const& renderer_template);
396@@ -65,13 +67,20 @@
397
398 /**
399 \brief Register an existing category instance with this registry.
400- Throws if category with sane id exists.
401+ \throws unity::InvalidArgumentException if a category with the same id exists already.
402 */
403 void register_category(Category::SCPtr category);
404
405+ /**
406+ \brief Serializes all categories in the registry.
407+ \return VariantArray containing all categories.
408+ */
409+ VariantArray serialize() const;
410+
411 private:
412 mutable std::mutex mutex_;
413- std::map<std::string, Category::SCPtr> categories_;
414+ typedef std::pair<std::string, Category::SCPtr> CatPair;
415+ std::vector<CatPair> categories_; // vector instead of map, so we preserve order
416 };
417
418 } // namespace internal
419
420=== modified file 'include/unity/scopes/internal/DfltConfig.h.in'
421--- include/unity/scopes/internal/DfltConfig.h.in 2014-11-03 05:31:30 +0000
422+++ include/unity/scopes/internal/DfltConfig.h.in 2015-01-13 07:11:02 +0000
423@@ -46,12 +46,20 @@
424
425 static constexpr char const* DFLT_SS_SCOPE_IDENTITY = "SmartScope";
426
427-static const int DFLT_REAP_EXPIRY = 45; // seconds
428-static const int DFLT_REAP_INTERVAL = 10; // seconds
429-static const int DFLT_PROCESS_TIMEOUT = 4000; // milliseconds
430-static const int DFLT_ZMQ_TWOWAY_TIMEOUT = 500; // milliseconds
431-static const int DFLT_ZMQ_LOCATE_TIMEOUT = 5000; // milliseconds
432-static const int DFLT_ZMQ_REGISTRY_TIMEOUT = 5000; // milliseconds
433+static constexpr int DFLT_REAP_EXPIRY = 45; // seconds
434+static constexpr int DFLT_REAP_INTERVAL = 10; // seconds
435+static constexpr int DFLT_PROCESS_TIMEOUT = 4000; // milliseconds
436+static constexpr int DFLT_ZMQ_TWOWAY_TIMEOUT = 500; // milliseconds
437+static constexpr int DFLT_ZMQ_LOCATE_TIMEOUT = 5000; // milliseconds
438+static constexpr int DFLT_ZMQ_REGISTRY_TIMEOUT = 5000; // milliseconds
439+
440+static constexpr char const* DFLT_HOME_CACHE_SUBDIR = ".local/share/unity-scopes";
441+static constexpr char const* DFLT_HOME_APP_SUBDIR = ".local/share";
442+static constexpr char const* DFLT_HOME_CONFIG_SUBDIR = ".config/unity-scopes";
443+static constexpr char const* DFLT_HOME_LOG_SUBDIR = ".cache/unity-scopes/logs";
444+
445+static constexpr int DFLT_MAX_LOG_FILE_SIZE = 512 * 1024; // bytes, individual file size
446+static constexpr int DFLT_MAX_LOG_DIR_SIZE = 10 * 1024 * 1024; // bytes, sum of file sizes
447
448 } // namespace internal
449
450
451=== modified file 'include/unity/scopes/internal/Logger.h'
452--- include/unity/scopes/internal/Logger.h 2014-11-25 23:31:51 +0000
453+++ include/unity/scopes/internal/Logger.h 2015-01-13 07:11:02 +0000
454@@ -19,6 +19,7 @@
455 #pragma once
456
457 #include <unity/util/DefinesPtrs.h>
458+#include <unity/util/NonCopyable.h>
459 #include <unity/util/ResourcePtr.h>
460
461 #define BOOST_LOG_DYN_LINK
462@@ -27,6 +28,10 @@
463 #include <boost/log/sources/global_logger_storage.hpp>
464 #include <boost/log/sources/record_ostream.hpp>
465 #include <boost/log/sources/severity_channel_logger.hpp>
466+#include <boost/log/utility/value_ref.hpp>
467+
468+#include <atomic>
469+#include <unordered_map>
470
471 namespace unity
472 {
473@@ -37,35 +42,76 @@
474 namespace internal
475 {
476
477+namespace
478+{
479+
480+#pragma GCC diagnostic push
481+#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
482+
483+BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", int)
484+BOOST_LOG_ATTRIBUTE_KEYWORD(channel, "Channel", std::string)
485+
486+#pragma GCC diagnostic pop
487+
488+}
489+
490 class Logger
491 {
492 public:
493+ NONCOPYABLE(Logger);
494 UNITY_DEFINES_PTRS(Logger);
495
496 // Instantiate a logger that logs to std::clog.
497 Logger(std::string const& id);
498 ~Logger();
499
500+ enum Channel
501+ {
502+ IPC,
503+ LastChannelEnum_
504+ };
505+
506+ // Returns default logger (no channel)
507 operator boost::log::sources::severity_channel_logger_mt<>&();
508
509- void set_log_file(std::string const& path);
510-
511- enum Severity { Trace, Info, Warning, Error, Fatal };
512+ // Returns logger for specified channel.
513+ boost::log::sources::severity_channel_logger_mt<>& operator()(Channel c);
514+
515+ void set_log_file(std::string const& path, int rotation_size, int dir_size);
516+
517+ enum Severity { Info, Warning, Error, Fatal, Trace };
518 Severity set_severity_threshold(Severity s);
519
520+ bool set_channel(Channel c, bool enable);
521+ bool set_channel(std::string channel_name, bool enable);
522+ void enable_channels(std::vector<std::string> const& names);
523+
524 private:
525- std::string scope_id_;
526- boost::log::sources::severity_channel_logger_mt<> logger_;
527-
528- typedef boost::log::sinks::synchronous_sink<boost::log::sinks::text_ostream_backend> ClogSinkT;
529+ bool filter(boost::log::value_ref<int, tag::severity> const& level,
530+ boost::log::value_ref<std::string, tag::channel> const& channel);
531+
532+ void formatter(boost::log::record_view const& rec,
533+ boost::log::formatting_ostream& strm);
534+
535+ std::string scope_id_; // immutable
536+
537+ boost::log::sources::severity_channel_logger_mt<> logger_; // Default logger, no channel, immutable
538+
539+ std::atomic<Severity> severity_;
540+
541+ typedef boost::log::sinks::asynchronous_sink<boost::log::sinks::text_ostream_backend> ClogSinkT;
542 typedef boost::shared_ptr<ClogSinkT> ClogSinkPtr;
543 ClogSinkPtr clog_sink_;
544
545- typedef boost::log::sinks::synchronous_sink<boost::log::sinks::text_file_backend> FileSinkT;
546+ typedef boost::log::sinks::asynchronous_sink<boost::log::sinks::text_file_backend> FileSinkT;
547 typedef boost::shared_ptr<FileSinkT> FileSinkPtr;
548 FileSinkPtr file_sink_;
549
550- Severity severity_;
551+ typedef std::pair<boost::log::sources::severity_channel_logger_mt<>, std::atomic_bool> ChannelData;
552+ typedef std::unordered_map<std::string, ChannelData> ChannelMap;
553+ ChannelMap channel_loggers_; // immutable
554+
555+ std::mutex mutex_; // Protects clog_sink_ and file_sink_
556 };
557
558 } // namespace internal
559
560=== modified file 'include/unity/scopes/internal/ObjectImpl.h'
561--- include/unity/scopes/internal/ObjectImpl.h 2014-11-20 05:32:53 +0000
562+++ include/unity/scopes/internal/ObjectImpl.h 2015-01-13 07:11:02 +0000
563@@ -18,7 +18,6 @@
564
565 #pragma once
566
567-#include<unity/scopes/internal/Logger.h>
568 #include<unity/scopes/internal/MWObjectProxyFwd.h>
569 #include<unity/scopes/Object.h>
570
571@@ -36,7 +35,7 @@
572 class ObjectImpl : public virtual Object, public virtual std::enable_shared_from_this<ObjectImpl>
573 {
574 public:
575- ObjectImpl(MWProxy const& mw_proxy, boost::log::sources::severity_channel_logger_mt<>& logger);
576+ ObjectImpl(MWProxy const& mw_proxy);
577 virtual ~ObjectImpl();
578
579 virtual std::string identity() override;
580@@ -59,8 +58,6 @@
581 MWProxy mw_proxy_;
582 std::mutex proxy_mutex_; // Protects mw_proxy_
583
584- boost::log::sources::severity_channel_logger_mt<>& logger_;
585-
586 private:
587 void check_proxy(); // Throws from operations if mw_proxy_ is null
588 };
589
590=== modified file 'include/unity/scopes/internal/PreviewQueryObject.h'
591--- include/unity/scopes/internal/PreviewQueryObject.h 2014-11-20 05:32:53 +0000
592+++ include/unity/scopes/internal/PreviewQueryObject.h 2015-01-13 07:11:02 +0000
593@@ -39,8 +39,7 @@
594
595 PreviewQueryObject(std::shared_ptr<PreviewQueryBase> const& preview_base,
596 MWReplyProxy const& reply,
597- MWQueryCtrlProxy const& ctrl,
598- boost::log::sources::severity_channel_logger_mt<>& logger);
599+ MWQueryCtrlProxy const& ctrl);
600 virtual ~PreviewQueryObject();
601 void run(MWReplyProxy const& reply, InvokeInfo const& info) noexcept override;
602
603
604=== modified file 'include/unity/scopes/internal/PreviewReplyImpl.h'
605--- include/unity/scopes/internal/PreviewReplyImpl.h 2014-11-20 05:32:53 +0000
606+++ include/unity/scopes/internal/PreviewReplyImpl.h 2015-01-13 07:11:02 +0000
607@@ -39,8 +39,7 @@
608 {
609 public:
610 PreviewReplyImpl(MWReplyProxy const& mw_proxy,
611- std::shared_ptr<QueryObjectBase>const & qo,
612- boost::log::sources::severity_channel_logger_mt<>& logger);
613+ std::shared_ptr<QueryObjectBase>const & qo);
614 virtual ~PreviewReplyImpl();
615
616 virtual bool register_layout(unity::scopes::ColumnLayoutList const& layouts) override;
617
618=== modified file 'include/unity/scopes/internal/QueryCtrlImpl.h'
619--- include/unity/scopes/internal/QueryCtrlImpl.h 2014-11-20 05:32:53 +0000
620+++ include/unity/scopes/internal/QueryCtrlImpl.h 2015-01-13 07:11:02 +0000
621@@ -37,9 +37,7 @@
622 class QueryCtrlImpl : public virtual unity::scopes::QueryCtrl, public virtual ObjectImpl
623 {
624 public:
625- QueryCtrlImpl(MWQueryCtrlProxy const& ctrl_proxy,
626- MWReplyProxy const& reply_proxy,
627- boost::log::sources::severity_channel_logger_mt<>& logger);
628+ QueryCtrlImpl(MWQueryCtrlProxy const& ctrl_proxy, MWReplyProxy const& reply_proxy);
629 virtual ~QueryCtrlImpl();
630
631 virtual void cancel() override;
632
633=== modified file 'include/unity/scopes/internal/QueryCtrlObjectBase.h'
634--- include/unity/scopes/internal/QueryCtrlObjectBase.h 2014-11-03 05:31:30 +0000
635+++ include/unity/scopes/internal/QueryCtrlObjectBase.h 2015-01-13 07:11:02 +0000
636@@ -19,7 +19,6 @@
637 #pragma once
638
639 #include <unity/scopes/internal/AbstractObject.h>
640-#include <unity/scopes/internal/InvokeInfo.h>
641
642 namespace unity
643 {
644@@ -30,6 +29,8 @@
645 namespace internal
646 {
647
648+class InvokeInfo;
649+
650 class QueryCtrlObjectBase : public AbstractObject
651 {
652 public:
653
654=== modified file 'include/unity/scopes/internal/QueryObject.h'
655--- include/unity/scopes/internal/QueryObject.h 2014-11-20 05:32:53 +0000
656+++ include/unity/scopes/internal/QueryObject.h 2015-01-13 07:11:02 +0000
657@@ -18,7 +18,6 @@
658
659 #pragma once
660
661-#include <unity/scopes/internal/Logger.h>
662 #include <unity/scopes/internal/MWReplyProxyFwd.h>
663 #include <unity/scopes/internal/MWQueryCtrlProxyFwd.h>
664 #include <unity/scopes/internal/QueryObjectBase.h>
665@@ -47,13 +46,11 @@
666
667 QueryObject(std::shared_ptr<QueryBase> const& query_base,
668 MWReplyProxy const& reply,
669- MWQueryCtrlProxy const& ctrl,
670- boost::log::sources::severity_channel_logger_mt<>&);
671+ MWQueryCtrlProxy const& ctrl);
672 QueryObject(std::shared_ptr<QueryBase> const& query_base,
673 int cardinality,
674 MWReplyProxy const& reply,
675- MWQueryCtrlProxy const& ctrl,
676- boost::log::sources::severity_channel_logger_mt<>& logger);
677+ MWQueryCtrlProxy const& ctrl);
678 virtual ~QueryObject();
679
680 // Remote operation implementations
681@@ -76,7 +73,6 @@
682 bool pushable_;
683 QueryObjectBase::SPtr self_;
684 int cardinality_;
685- boost::log::sources::severity_channel_logger_mt<>& logger_;
686 mutable std::mutex mutex_;
687 };
688
689
690=== modified file 'include/unity/scopes/internal/QueryObjectBase.h'
691--- include/unity/scopes/internal/QueryObjectBase.h 2014-11-03 05:31:30 +0000
692+++ include/unity/scopes/internal/QueryObjectBase.h 2015-01-13 07:11:02 +0000
693@@ -19,7 +19,6 @@
694 #pragma once
695
696 #include <unity/scopes/internal/AbstractObject.h>
697-#include <unity/scopes/internal/InvokeInfo.h>
698 #include <unity/scopes/internal/MWReplyProxyFwd.h>
699 #include <unity/util/DefinesPtrs.h>
700
701@@ -32,6 +31,8 @@
702 namespace internal
703 {
704
705+class InvokeInfo;
706+
707 class QueryObjectBase : public AbstractObject
708 {
709 public:
710
711=== modified file 'include/unity/scopes/internal/RegistryImpl.h'
712--- include/unity/scopes/internal/RegistryImpl.h 2014-11-03 05:31:30 +0000
713+++ include/unity/scopes/internal/RegistryImpl.h 2015-01-13 07:11:02 +0000
714@@ -31,12 +31,10 @@
715 namespace internal
716 {
717
718-class RuntimeImpl;
719-
720 class RegistryImpl : public virtual unity::scopes::Registry, public virtual ObjectImpl
721 {
722 public:
723- RegistryImpl(MWRegistryProxy const& mw_proxy, RuntimeImpl* runtime);
724+ RegistryImpl(MWRegistryProxy const& mw_proxy);
725 ~RegistryImpl();
726
727 virtual ScopeMetadata get_metadata(std::string const& scope_id) override;
728
729=== modified file 'include/unity/scopes/internal/ReplyImpl.h'
730--- include/unity/scopes/internal/ReplyImpl.h 2014-11-20 05:32:53 +0000
731+++ include/unity/scopes/internal/ReplyImpl.h 2015-01-13 07:11:02 +0000
732@@ -41,9 +41,7 @@
733 class ReplyImpl : public virtual unity::scopes::Reply, public virtual ObjectImpl
734 {
735 public:
736- ReplyImpl(MWReplyProxy const& mw_proxy,
737- std::shared_ptr<QueryObjectBase>const & qo,
738- boost::log::sources::severity_channel_logger_mt<>& logger);
739+ ReplyImpl(MWReplyProxy const& mw_proxy, std::shared_ptr<QueryObjectBase>const & qo);
740 virtual ~ReplyImpl();
741
742 virtual void finished() override;
743
744=== modified file 'include/unity/scopes/internal/ReplyObject.h'
745--- include/unity/scopes/internal/ReplyObject.h 2014-11-20 05:32:53 +0000
746+++ include/unity/scopes/internal/ReplyObject.h 2015-01-13 07:11:02 +0000
747@@ -35,6 +35,7 @@
748 namespace internal
749 {
750
751+class InvokeInfo;
752 class RuntimeImpl;
753
754 // A ReplyObject sits in between the incoming requests from the middleware layer and the
755
756=== modified file 'include/unity/scopes/internal/RuntimeConfig.h'
757--- include/unity/scopes/internal/RuntimeConfig.h 2014-11-13 02:31:13 +0000
758+++ include/unity/scopes/internal/RuntimeConfig.h 2015-01-13 07:11:02 +0000
759@@ -47,9 +47,15 @@
760 std::string cache_directory() const;
761 std::string app_directory() const;
762 std::string config_directory() const;
763+ std::string log_directory() const;
764+ int max_log_file_size() const;
765+ int max_log_dir_size() const;
766+ std::vector<std::string> trace_channels() const;
767+
768 static std::string default_cache_directory();
769 static std::string default_app_directory();
770 static std::string default_config_directory();
771+ static std::string default_log_directory();
772
773 private:
774 std::string registry_identity_;
775@@ -63,6 +69,10 @@
776 std::string cache_directory_;
777 std::string app_directory_;
778 std::string config_directory_;
779+ std::string log_directory_;
780+ int max_log_file_size_;
781+ int max_log_dir_size_;
782+ std::vector<std::string> trace_channels_;
783 };
784
785 } // namespace internal
786
787=== modified file 'include/unity/scopes/internal/RuntimeImpl.h'
788--- include/unity/scopes/internal/RuntimeImpl.h 2014-12-04 04:33:50 +0000
789+++ include/unity/scopes/internal/RuntimeImpl.h 2015-01-13 07:11:02 +0000
790@@ -54,6 +54,7 @@
791 ThreadPool::SPtr async_pool() const;
792 ThreadSafeQueue<std::future<void>>::SPtr future_queue() const;
793 boost::log::sources::severity_channel_logger_mt<>& logger() const;
794+ boost::log::sources::severity_channel_logger_mt<>& logger(Logger::Channel channel) const;
795 void run_scope(ScopeBase* scope_base,
796 std::string const& scope_ini_file,
797 std::promise<void> ready_promise = std::promise<void>());
798@@ -61,6 +62,9 @@
799 ObjectProxy string_to_proxy(std::string const& s) const;
800 std::string proxy_to_string(ObjectProxy const& proxy) const;
801
802+ std::string cache_directory() const;
803+ std::string tmp_directory() const;
804+
805 ~RuntimeImpl();
806
807 private:
808@@ -88,7 +92,6 @@
809 std::string cache_dir_;
810 std::string app_dir_;
811 std::string config_dir_;
812- std::string tmp_dir_;
813 Logger::UPtr logger_;
814 mutable Reaper::SPtr reply_reaper_;
815 mutable ThreadPool::SPtr async_pool_; // Pool of invocation threads for async query creation
816
817=== modified file 'include/unity/scopes/internal/ScopeImpl.h'
818--- include/unity/scopes/internal/ScopeImpl.h 2014-11-03 05:31:30 +0000
819+++ include/unity/scopes/internal/ScopeImpl.h 2015-01-13 07:11:02 +0000
820@@ -45,7 +45,7 @@
821 class ScopeImpl : public virtual unity::scopes::Scope, public virtual ObjectImpl
822 {
823 public:
824- ScopeImpl(MWScopeProxy const& mw_proxy, RuntimeImpl* runtime, std::string const& scope_id);
825+ ScopeImpl(MWScopeProxy const& mw_proxy, std::string const& scope_id);
826 virtual ~ScopeImpl();
827
828 virtual QueryCtrlProxy search(std::string const& q,
829@@ -81,7 +81,7 @@
830 ActionMetadata const& hints,
831 PreviewListenerBase::SPtr const& reply) override;
832
833- static ScopeProxy create(MWScopeProxy const& mw_proxy, RuntimeImpl* runtime, std::string const& scope_id);
834+ static ScopeProxy create(MWScopeProxy const& mw_proxy, std::string const& scope_id);
835
836 private:
837 MWScopeProxy fwd();
838
839=== modified file 'include/unity/scopes/internal/ScopeObject.h'
840--- include/unity/scopes/internal/ScopeObject.h 2014-11-03 05:31:30 +0000
841+++ include/unity/scopes/internal/ScopeObject.h 2015-01-13 07:11:02 +0000
842@@ -40,7 +40,6 @@
843 {
844
845 class MiddlewareBase;
846-class RuntimeImpl;
847
848 // A ScopeObject sits in between the incoming requests from the middleware layer and the
849 // ScopeBase-derived implementation provided by the scope. It forwards incoming
850@@ -51,7 +50,7 @@
851 public:
852 UNITY_DEFINES_PTRS(ScopeObject);
853
854- ScopeObject(RuntimeImpl* runtime, ScopeBase* scope_base, bool debug_mode = false);
855+ ScopeObject(ScopeBase* scope_base, bool debug_mode = false);
856 virtual ~ScopeObject();
857
858 // Remote operation implementations
859@@ -83,7 +82,6 @@
860 MWQueryCtrlProxy query(MWReplyProxy const& reply, MiddlewareBase* mw_base,
861 std::function<QueryBase::SPtr(void)> const& query_factory_fun,
862 std::function<QueryObjectBase::SPtr(QueryBase::SPtr, MWQueryCtrlProxy)> const& query_object_factory_fun);
863- RuntimeImpl* const runtime_;
864 ScopeBase* const scope_base_;
865 bool const debug_mode_;
866 };
867
868=== modified file 'include/unity/scopes/internal/ScopeObjectBase.h'
869--- include/unity/scopes/internal/ScopeObjectBase.h 2014-11-20 05:32:53 +0000
870+++ include/unity/scopes/internal/ScopeObjectBase.h 2015-01-13 07:11:02 +0000
871@@ -19,7 +19,6 @@
872 #pragma once
873
874 #include <unity/scopes/internal/AbstractObject.h>
875-#include <unity/scopes/internal/InvokeInfo.h>
876 #include <unity/scopes/internal/MWQueryCtrlProxyFwd.h>
877 #include <unity/scopes/internal/MWReplyProxyFwd.h>
878 #include <unity/scopes/Result.h>
879@@ -39,6 +38,8 @@
880 namespace internal
881 {
882
883+class InvokeInfo;
884+
885 class ScopeObjectBase : public AbstractObject
886 {
887 public:
888
889=== modified file 'include/unity/scopes/internal/SearchReplyImpl.h'
890--- include/unity/scopes/internal/SearchReplyImpl.h 2014-11-20 05:32:53 +0000
891+++ include/unity/scopes/internal/SearchReplyImpl.h 2015-01-13 07:11:02 +0000
892@@ -53,8 +53,8 @@
893 SearchReplyImpl(MWReplyProxy const& mw_proxy,
894 std::shared_ptr<QueryObjectBase>const & qo,
895 int cardinality,
896- std::string const& current_department_id,
897- boost::log::sources::severity_channel_logger_mt<>& logger);
898+ std::string const& query_string,
899+ std::string const& current_department_id);
900 virtual ~SearchReplyImpl();
901
902 virtual void register_departments(Department::SCPtr const& parent) override;
903@@ -76,14 +76,25 @@
904 virtual bool push(unity::scopes::CategorisedResult const& result) override;
905 virtual bool push(unity::scopes::Filters const& filters, unity::scopes::FilterState const& filter_state) override;
906
907+ virtual void finished() override;
908+
909+ virtual void push_surfacing_results_from_cache() noexcept;
910+
911 private:
912 bool push(Category::SCPtr category);
913+ void write_cached_results() noexcept;
914
915 std::shared_ptr<CategoryRegistry> cat_registry_;
916
917 std::atomic_int cardinality_;
918 std::atomic_int num_pushes_;
919+ std::atomic_bool finished_;
920+ std::string query_string_;
921 std::string current_department_;
922+
923+ std::vector<unity::scopes::CategorisedResult> cached_results_;
924+ Department::SCPtr cached_departments_;
925+ std::mutex mutex_;
926 };
927
928 } // namespace internal
929
930=== modified file 'include/unity/scopes/internal/smartscopes/SSQueryObject.h'
931--- include/unity/scopes/internal/smartscopes/SSQueryObject.h 2014-11-20 05:32:53 +0000
932+++ include/unity/scopes/internal/smartscopes/SSQueryObject.h 2015-01-13 07:11:02 +0000
933@@ -18,7 +18,6 @@
934
935 #pragma once
936
937-#include <unity/scopes/internal/Logger.h>
938 #include <unity/scopes/internal/QueryObjectBase.h>
939 #include <unity/scopes/ReplyProxyFwd.h>
940
941@@ -68,7 +67,7 @@
942 public:
943 UNITY_DEFINES_PTRS(SSQueryObject);
944
945- SSQueryObject(boost::log::sources::severity_channel_logger_mt<>& logger);
946+ SSQueryObject();
947 virtual ~SSQueryObject();
948
949 // Remote operation implementations
950@@ -98,7 +97,6 @@
951 mutable std::mutex queries_mutex_;
952
953 std::map<std::string, SSQuery::SPtr> queries_; // reply ID : query
954- boost::log::sources::severity_channel_logger_mt<>& logger_;
955 };
956
957 } // namespace smartscopes
958
959=== modified file 'include/unity/scopes/internal/smartscopes/SSScopeObject.h'
960--- include/unity/scopes/internal/smartscopes/SSScopeObject.h 2014-11-20 05:32:53 +0000
961+++ include/unity/scopes/internal/smartscopes/SSScopeObject.h 2015-01-13 07:11:02 +0000
962@@ -88,8 +88,6 @@
963
964 std::unique_ptr<SmartScope> const smartscope_;
965 SSRegistryObject::SPtr ss_registry_;
966-
967- boost::log::sources::severity_channel_logger_mt<>& logger_;
968 };
969
970 } // namespace smartscopes
971
972=== modified file 'include/unity/scopes/internal/smartscopes/SmartScopesClient.h'
973--- include/unity/scopes/internal/smartscopes/SmartScopesClient.h 2014-12-09 11:34:26 +0000
974+++ include/unity/scopes/internal/smartscopes/SmartScopesClient.h 2015-01-13 07:11:02 +0000
975@@ -20,9 +20,9 @@
976
977 #include <unity/scopes/FilterBase.h>
978 #include <unity/scopes/FilterState.h>
979-#include <unity/scopes/internal/smartscopes/HttpClientInterface.h>
980 #include <unity/scopes/internal/JsonNodeInterface.h>
981 #include <unity/scopes/internal/Logger.h>
982+#include <unity/scopes/internal/smartscopes/HttpClientInterface.h>
983 #include <unity/scopes/internal/UniqueID.h>
984
985 #include <unity/util/NonCopyable.h>
986@@ -43,6 +43,8 @@
987 namespace internal
988 {
989
990+class RuntimeImpl;
991+
992 namespace smartscopes
993 {
994
995@@ -166,7 +168,7 @@
996
997 SmartScopesClient(HttpClientInterface::SPtr http_client,
998 JsonNodeInterface::SPtr json_node,
999- boost::log::sources::severity_channel_logger_mt<>& logger_,
1000+ RuntimeImpl* runtime,
1001 std::string const& url = "", // detect url
1002 std::string const& partner_id_path = "");
1003
1004@@ -227,6 +229,7 @@
1005
1006 HttpClientInterface::SPtr http_client_;
1007 JsonNodeInterface::SPtr json_node_;
1008+ RuntimeImpl* runtime_;
1009 boost::log::sources::severity_channel_logger_mt<>& logger_;
1010 std::string url_;
1011
1012
1013=== modified file 'include/unity/scopes/internal/zmq_middleware/ObjectAdapter.h'
1014--- include/unity/scopes/internal/zmq_middleware/ObjectAdapter.h 2014-11-20 05:32:53 +0000
1015+++ include/unity/scopes/internal/zmq_middleware/ObjectAdapter.h 2015-01-13 07:11:02 +0000
1016@@ -19,6 +19,7 @@
1017 #pragma once
1018
1019 #include <unity/scopes/internal/Logger.h>
1020+#include <unity/scopes/internal/zmq_middleware/Current.h>
1021 #include <unity/scopes/internal/zmq_middleware/ZmqObjectProxy.h>
1022 #include <unity/scopes/ScopeExceptions.h>
1023 #include <unity/util/NonCopyable.h>
1024@@ -108,6 +109,12 @@
1025
1026 void store_exception(scopes::MiddlewareException& ex);
1027
1028+ boost::log::sources::severity_channel_logger_mt<>& logger() const;
1029+ boost::log::sources::severity_channel_logger_mt<>& ipc_logger() const;
1030+
1031+ void trace_dispatch(Current const& c);
1032+ void trace_response();
1033+
1034 ZmqMiddleware& mw_;
1035 std::string name_;
1036 std::string endpoint_;
1037@@ -124,8 +131,6 @@
1038 std::condition_variable state_changed_;
1039 mutable std::mutex state_mutex_;
1040
1041- boost::log::sources::severity_channel_logger_mt<>& logger_;
1042-
1043 // Map of object identity and servant pairs
1044 typedef std::unordered_map<std::string, std::shared_ptr<ServantBase>> ServantMap;
1045 ServantMap servants_;
1046
1047=== modified file 'include/unity/scopes/internal/zmq_middleware/ZmqException.h'
1048--- include/unity/scopes/internal/zmq_middleware/ZmqException.h 2014-11-03 05:31:30 +0000
1049+++ include/unity/scopes/internal/zmq_middleware/ZmqException.h 2015-01-13 07:11:02 +0000
1050@@ -48,7 +48,10 @@
1051 kj::ArrayPtr<kj::ArrayPtr<capnp::word const> const> create_object_not_exist_response(capnp::MessageBuilder& b,
1052 Current const& c);
1053
1054-void throw_if_runtime_exception(capnproto::Response::Reader const& reader);
1055+void throw_if_runtime_exception(capnproto::Response::Reader const& response);
1056+
1057+std::string decode_runtime_exception(capnproto::Response::Reader const& response);
1058+std::string decode_status(capnproto::Response::Reader const& response);
1059
1060 } // namespace zmq_middleware
1061
1062
1063=== modified file 'include/unity/scopes/internal/zmq_middleware/ZmqObjectProxy.h'
1064--- include/unity/scopes/internal/zmq_middleware/ZmqObjectProxy.h 2014-11-03 05:31:30 +0000
1065+++ include/unity/scopes/internal/zmq_middleware/ZmqObjectProxy.h 2015-01-13 07:11:02 +0000
1066@@ -72,7 +72,7 @@
1067 protected:
1068 capnproto::Request::Builder make_request_(capnp::MessageBuilder& b, std::string const& operation_name) const;
1069
1070- void invoke_oneway_(capnp::MessageBuilder& out_params);
1071+ void invoke_oneway_(capnp::MessageBuilder& in_params);
1072
1073 // Holds both the receiver for the unmarshaling buffer (which allocates memory)
1074 // and the reader that decodes the memory from the unmarshaling buffer.
1075@@ -89,13 +89,19 @@
1076 std::unique_ptr<capnp::SegmentArrayMessageReader> reader;
1077 };
1078
1079- TwowayOutParams invoke_twoway_(capnp::MessageBuilder& in_params);
1080- TwowayOutParams invoke_twoway_(capnp::MessageBuilder& in_params,
1081+ TwowayOutParams invoke_twoway_(capnp::MessageBuilder& request);
1082+ TwowayOutParams invoke_twoway_(capnp::MessageBuilder& request,
1083 int64_t twoway_timeout,
1084 int64_t locate_timeout = -1);
1085
1086 private:
1087- TwowayOutParams invoke_twoway__(capnp::MessageBuilder& in_params, int64_t timeout);
1088+ TwowayOutParams invoke_twoway__(capnp::MessageBuilder& request, int64_t timeout);
1089+
1090+ std::string decode_request_(capnp::MessageBuilder& request);
1091+ void trace_request_(capnp::MessageBuilder& request);
1092+
1093+ std::string decode_reply_(capnp::MessageBuilder& request, capnp::MessageReader& reply);
1094+ void trace_reply_(capnp::MessageBuilder& request, capnp::MessageReader& reply);
1095
1096 std::string endpoint_;
1097 std::string identity_;
1098
1099=== modified file 'include/unity/scopes/testing/MockSearchReply.h'
1100--- include/unity/scopes/testing/MockSearchReply.h 2014-11-03 05:31:30 +0000
1101+++ include/unity/scopes/testing/MockSearchReply.h 2015-01-13 07:11:02 +0000
1102@@ -65,6 +65,7 @@
1103 MOCK_METHOD1(push, bool(CategorisedResult const&));
1104 MOCK_METHOD2(push, bool(Filters const&, FilterState const&));
1105 MOCK_METHOD1(push, bool(experimental::Annotation const& annotation));
1106+ MOCK_METHOD0(push_surfacing_results_from_cache, void());
1107 };
1108
1109 /// @endcond
1110
1111=== modified file 'include/unity/scopes/utility/internal/BufferedSearchReplyImpl.h'
1112--- include/unity/scopes/utility/internal/BufferedSearchReplyImpl.h 2014-12-01 01:51:38 +0000
1113+++ include/unity/scopes/utility/internal/BufferedSearchReplyImpl.h 2015-01-13 07:11:02 +0000
1114@@ -18,13 +18,14 @@
1115
1116 #pragma once
1117
1118+#include <unity/scopes/CategorisedResult.h>
1119 #include <unity/scopes/SearchReply.h>
1120 #include <unity/scopes/SearchReplyProxyFwd.h>
1121-#include <unity/scopes/CategorisedResult.h>
1122+
1123+#include <atomic>
1124 #include <memory>
1125+#include <mutex>
1126 #include <vector>
1127-#include <mutex>
1128-#include <atomic>
1129
1130 namespace unity
1131 {
1132@@ -62,6 +63,8 @@
1133 bool push(unity::scopes::CategorisedResult const& result) override;
1134 bool push(unity::scopes::Filters const& filters, unity::scopes::FilterState const& filter_state) override;
1135
1136+ void push_surfacing_results_from_cache() override;
1137+
1138 // Reply interface
1139 void finished() override;
1140 void error(std::exception_ptr ex) override;
1141
1142=== modified file 'scoperegistry/DirWatcher.cpp'
1143--- scoperegistry/DirWatcher.cpp 2014-12-02 04:18:44 +0000
1144+++ scoperegistry/DirWatcher.cpp 2015-01-13 07:11:02 +0000
1145@@ -137,12 +137,11 @@
1146 }
1147 catch (std::exception const& e)
1148 {
1149- BOOST_LOG_SEV(logger_, Logger::Error) << "~DirWatcher(): " << e.what();
1150+ BOOST_LOG(logger_) << "~DirWatcher(): " << e.what();
1151 }
1152 catch (...)
1153 {
1154- BOOST_LOG_SEV(logger_, Logger::Error)
1155- << "~DirWatcher(): watch_thread was aborted due to an unknown exception";
1156+ BOOST_LOG(logger_) << "~DirWatcher(): watch_thread was aborted due to an unknown exception";
1157 }
1158 }
1159 else
1160@@ -178,8 +177,6 @@
1161 #pragma GCC diagnostic pop
1162
1163 int bytes_avail = 0;
1164- static_assert(std::alignment_of<char*>::value >= std::alignment_of<struct inotify_event>::value,
1165- "cannot use std::string as buffer for inotify events");
1166 std::string buffer;
1167 std::string event_path;
1168
1169@@ -223,7 +220,12 @@
1170 int i = 0;
1171 while (i < bytes_read)
1172 {
1173+ static_assert(std::alignment_of<char*>::value >= std::alignment_of<struct inotify_event>::value,
1174+ "cannot use std::string as buffer for inotify events");
1175+#pragma GCC diagnostic push
1176+#pragma GCC diagnostic ignored "-Wcast-align"
1177 auto event = reinterpret_cast<inotify_event const*>(&buffer[i]);
1178+#pragma GCC diagnostic pop
1179 {
1180 event_path = "";
1181 std::lock_guard<std::mutex> lock(mutex_);
1182@@ -281,14 +283,14 @@
1183 }
1184 catch (std::exception const& e)
1185 {
1186- BOOST_LOG_SEV(logger_, Logger::Error) << e.what();
1187+ BOOST_LOG(logger_) << "DirWatcher::watch_thread(): " << e.what();
1188 std::lock_guard<std::mutex> lock(mutex_);
1189 thread_state_ = Failed;
1190 thread_exception_ = std::current_exception();
1191 }
1192 catch (...)
1193 {
1194- BOOST_LOG_SEV(logger_, Logger::Error) << "DirWatcher::watch_thread(): Thread aborted: unknown exception";
1195+ BOOST_LOG(logger_) << "DirWatcher::watch_thread(): Thread aborted: unknown exception";
1196 std::lock_guard<std::mutex> lock(mutex_);
1197 thread_state_ = Failed;
1198 thread_exception_ = std::current_exception();
1199
1200=== modified file 'scoperegistry/ScopesWatcher.cpp'
1201--- scoperegistry/ScopesWatcher.cpp 2014-11-28 06:41:23 +0000
1202+++ scoperegistry/ScopesWatcher.cpp 2015-01-13 07:11:02 +0000
1203@@ -60,7 +60,7 @@
1204 catch (unity::LogicException const&) {} // Ignore already exists exception
1205 catch (unity::SyscallException const& e)
1206 {
1207- BOOST_LOG_SEV(logger_, Logger::Error) << "ScopesWatcher::add_install_dir(): parent dir watch: " << e.what();
1208+ BOOST_LOG(logger_) << "ScopesWatcher::add_install_dir(): parent dir watch: " << e.what();
1209 }
1210
1211 // Create a new entry for this install dir into idir_to_sdirs_map_
1212@@ -101,11 +101,11 @@
1213 }
1214 catch (unity::ResourceException const& e)
1215 {
1216- BOOST_LOG_SEV(logger_, Logger::Error) << "ScopesWatcher::add_install_dir(): install dir watch: " << e.what();
1217+ BOOST_LOG(logger_) << "ScopesWatcher::add_install_dir(): install dir watch: " << e.what();
1218 }
1219 catch (unity::SyscallException const& e)
1220 {
1221- BOOST_LOG_SEV(logger_, Logger::Error) << "ScopesWatcher::add_install_dir(): install dir watch: " << e.what();
1222+ BOOST_LOG(logger_) << "ScopesWatcher::add_install_dir(): install dir watch: " << e.what();
1223 }
1224 }
1225
1226@@ -199,7 +199,7 @@
1227 }
1228 catch (std::exception const& e)
1229 {
1230- BOOST_LOG_SEV(logger_, Logger::Error) << "scoperegistry: add_scope_dir(): " << e.what();
1231+ BOOST_LOG(logger_) << "scoperegistry: add_scope_dir(): " << e.what();
1232 }
1233 }
1234
1235
1236=== modified file 'scoperegistry/scoperegistry.cpp'
1237--- scoperegistry/scoperegistry.cpp 2014-12-09 15:05:13 +0000
1238+++ scoperegistry/scoperegistry.cpp 2015-01-13 07:11:02 +0000
1239@@ -408,7 +408,7 @@
1240 {
1241 }
1242
1243- ScopeProxy proxy = ScopeImpl::create(mw->create_scope_proxy(scope.first), mw->runtime(), scope.first);
1244+ ScopeProxy proxy = ScopeImpl::create(mw->create_scope_proxy(scope.first), scope.first);
1245 mi->set_proxy(proxy);
1246 auto meta = ScopeMetadataImpl::create(std::move(mi));
1247
1248
1249=== modified file 'src/scopes/internal/ActivationQueryObject.cpp'
1250--- src/scopes/internal/ActivationQueryObject.cpp 2014-11-18 07:04:04 +0000
1251+++ src/scopes/internal/ActivationQueryObject.cpp 2015-01-13 07:11:02 +0000
1252@@ -17,10 +17,12 @@
1253 */
1254
1255 #include <unity/scopes/internal/ActivationQueryObject.h>
1256-#include <unity/scopes/ListenerBase.h>
1257+
1258 #include <unity/scopes/ActivationQueryBase.h>
1259+#include <unity/scopes/internal/MWQueryCtrl.h>
1260 #include <unity/scopes/internal/MWReply.h>
1261-#include <unity/scopes/internal/MWQueryCtrl.h>
1262+#include <unity/scopes/internal/RuntimeImpl.h>
1263+#include <unity/scopes/ListenerBase.h>
1264
1265 #include <cassert>
1266
1267@@ -38,9 +40,8 @@
1268
1269 ActivationQueryObject::ActivationQueryObject(std::shared_ptr<ActivationQueryBase> const& act_base,
1270 MWReplyProxy const& reply,
1271- MWQueryCtrlProxy const& ctrl,
1272- boost::log::sources::severity_channel_logger_mt<>& logger)
1273- : QueryObject(act_base, reply, ctrl, logger)
1274+ MWQueryCtrlProxy const& ctrl)
1275+ : QueryObject(act_base, reply, ctrl)
1276 , act_base_(act_base)
1277 {
1278 }
1279@@ -50,7 +51,7 @@
1280 // parent destructor will call ctrl_->destroy()
1281 }
1282
1283-void ActivationQueryObject::run(MWReplyProxy const& reply, InvokeInfo const& /* info */) noexcept
1284+void ActivationQueryObject::run(MWReplyProxy const& reply, InvokeInfo const& info) noexcept
1285 {
1286 assert(self_);
1287
1288@@ -70,12 +71,12 @@
1289 }
1290 catch (std::exception const& e)
1291 {
1292- BOOST_LOG_SEV(logger_, Logger::Error) << "ActivationQueryObject::run(): " << e.what();
1293+ BOOST_LOG(info.mw->runtime()->logger()) << "ActivationQueryObject::run(): " << e.what();
1294 reply_->finished(CompletionDetails(CompletionDetails::Error, e.what())); // Oneway, can't block
1295 }
1296 catch (...)
1297 {
1298- BOOST_LOG_SEV(logger_, Logger::Error) << "ActivationQueryObject::run(): unknown exception";
1299+ BOOST_LOG(info.mw->runtime()->logger()) << "ActivationQueryObject::run(): unknown exception";
1300 reply_->finished(CompletionDetails(CompletionDetails::Error, "unknown exception")); // Oneway, can't block
1301 }
1302 }
1303
1304=== modified file 'src/scopes/internal/CategoryRegistry.cpp'
1305--- src/scopes/internal/CategoryRegistry.cpp 2014-07-02 09:36:34 +0000
1306+++ src/scopes/internal/CategoryRegistry.cpp 2015-01-13 07:11:02 +0000
1307@@ -18,6 +18,8 @@
1308
1309 #include <unity/scopes/internal/CategoryRegistry.h>
1310 #include <unity/UnityExceptions.h>
1311+
1312+#include <algorithm>
1313 #include <sstream>
1314
1315 namespace unity
1316@@ -32,13 +34,13 @@
1317 void CategoryRegistry::register_category(Category::SCPtr category)
1318 {
1319 std::lock_guard<decltype(mutex_)> lock(mutex_);
1320- if (categories_.find(category->id()) != categories_.end())
1321+ auto id = category->id();
1322+ auto it = find_if(categories_.begin(), categories_.end(), [id](const CatPair& p) { return p.first == id; });
1323+ if (it != categories_.end())
1324 {
1325- std::ostringstream s;
1326- s << "Category " << category->id() << " already defined";
1327- throw InvalidArgumentException(s.str());
1328+ throw InvalidArgumentException("register_category(): duplicate category: " + id);
1329 }
1330- categories_[category->id()] = category;
1331+ categories_.push_back(make_pair(category->id(), category));
1332 }
1333
1334 Category::SCPtr CategoryRegistry::register_category(VariantMap const& variant_map)
1335@@ -58,7 +60,7 @@
1336 Category::SCPtr CategoryRegistry::lookup_category(std::string const& id) const
1337 {
1338 std::lock_guard<decltype(mutex_)> lock(mutex_);
1339- auto it = categories_.find(id);
1340+ auto it = find_if(categories_.begin(), categories_.end(), [id](const CatPair& p) { return p.first == id; });
1341 if (it != categories_.end())
1342 {
1343 return it->second;
1344@@ -66,6 +68,17 @@
1345 return nullptr;
1346 }
1347
1348+VariantArray CategoryRegistry::serialize() const
1349+{
1350+ std::lock_guard<decltype(mutex_)> lock(mutex_);
1351+ VariantArray va;
1352+ for (auto&& p : categories_)
1353+ {
1354+ va.push_back(Variant(p.second->serialize()));
1355+ }
1356+ return va;
1357+}
1358+
1359 } // namespace internal
1360
1361 } // namespace scopes
1362
1363=== modified file 'src/scopes/internal/JsonCppNode.cpp'
1364--- src/scopes/internal/JsonCppNode.cpp 2014-08-18 08:12:22 +0000
1365+++ src/scopes/internal/JsonCppNode.cpp 2015-01-13 07:11:02 +0000
1366@@ -276,7 +276,7 @@
1367 return std::make_shared<JsonCppNode>(value_node);
1368 }
1369
1370-JsonNodeInterface::SPtr JsonCppNode::get_node(uint node_index) const
1371+JsonNodeInterface::SPtr JsonCppNode::get_node(unsigned int node_index) const
1372 {
1373 if (root_.type() != Json::arrayValue)
1374 {
1375
1376=== modified file 'src/scopes/internal/Logger.cpp'
1377--- src/scopes/internal/Logger.cpp 2014-12-01 12:41:49 +0000
1378+++ src/scopes/internal/Logger.cpp 2015-01-13 07:11:02 +0000
1379@@ -24,7 +24,9 @@
1380 #include <boost/log/sources/record_ostream.hpp>
1381 #include <boost/log/support/date_time.hpp>
1382 #include <boost/log/trivial.hpp>
1383+#include <boost/phoenix/bind.hpp>
1384 #include <boost/utility/empty_deleter.hpp>
1385+#include <unity/UnityExceptions.h>
1386
1387 using namespace std;
1388
1389@@ -47,9 +49,14 @@
1390 namespace
1391 {
1392
1393-string const& severity(int s)
1394+static array<string, Logger::LastChannelEnum_> const channel_names =
1395+ {
1396+ "IPC"
1397+ };
1398+
1399+string const& to_severity(int s)
1400 {
1401- static array<string, 5> const severities = { { "TRACE", "INFO", "WARNING", "ERROR", "FATAL" } };
1402+ static array<string, 5> const severities = { { "INFO", "WARNING", "ERROR", "FATAL", "TRACE" } };
1403 static string const unknown = "UNKNOWN";
1404
1405 if (s < 0 || s >= static_cast<int>(severities.size()))
1406@@ -59,31 +66,13 @@
1407 return severities[s];
1408 }
1409
1410-void formatter(logging::record_view const& rec, logging::formatting_ostream& strm, string const& scope_id)
1411-{
1412- strm << "[" << expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d %H:%M:%S.%f")(rec) << "] "
1413- << severity(expr::attr<int>("Severity")(rec).get()) << ": "
1414- << scope_id << ": "
1415- << rec[expr::smessage];
1416-}
1417-
1418 }
1419
1420 // Instantiate a logger for the scope/client with the given ID.
1421-//
1422-// Note: channel is our own address in memory. This gives
1423-// us a unique identity. The id passed by the run time
1424-// is *not* necessarily unique. (It is normally, but
1425-// some of the tests instantiate more than one run time
1426-// in a single address space, not always necessarily with
1427-// a unique scope id. Using a unique ID guarantees
1428-// that a log message writting by one run time isn't
1429-// also written a second time by a run time that
1430-// happens to have the same ID.
1431
1432 Logger::Logger(string const& scope_id)
1433 : scope_id_(scope_id)
1434- , logger_(keywords::channel = to_string(reinterpret_cast<ptrdiff_t>(this)))
1435+ , logger_(keywords::severity = Logger::Error)
1436 , severity_(Logger::Info)
1437 {
1438 namespace ph = std::placeholders;
1439@@ -92,11 +81,21 @@
1440
1441 logger_.add_attribute("TimeStamp", attrs::local_clock());
1442
1443+ // Create a channel logger for each channel.
1444+ for (auto&& name : channel_names)
1445+ {
1446+ auto clogger = boost::log::sources::severity_channel_logger_mt<>(keywords::severity = Logger::Trace,
1447+ keywords::channel = name);
1448+ clogger.add_attribute("TimeStamp", attrs::local_clock());
1449+ channel_loggers_[name] = make_pair(clogger, false);
1450+ }
1451+
1452 // Set up sink that logs to std::clog.
1453 clog_sink_ = boost::make_shared<ClogSinkT>();
1454- clog_sink_->set_formatter(std::bind(formatter, ph::_1, ph::_2, scope_id));
1455+ clog_sink_->set_formatter(bind(&Logger::formatter, this, ph::_1, ph::_2));
1456 boost::shared_ptr<std::ostream> console_stream(&std::clog, boost::empty_deleter());
1457 clog_sink_->locked_backend()->add_stream(console_stream);
1458+ clog_sink_->locked_backend()->auto_flush(true);
1459 logging::core::get()->add_sink(clog_sink_);
1460
1461 set_severity_threshold(severity_);
1462@@ -104,49 +103,113 @@
1463
1464 Logger::~Logger()
1465 {
1466+ lock_guard<mutex> lock(mutex_);
1467+
1468 if (clog_sink_)
1469 {
1470 logging::core::get()->remove_sink(clog_sink_);
1471+ clog_sink_->stop();
1472+ clog_sink_->flush();
1473 }
1474 else
1475 {
1476 logging::core::get()->remove_sink(file_sink_);
1477- }
1478-}
1479-
1480-Logger::operator src::severity_channel_logger_mt<>&()
1481-{
1482- return logger_;
1483-}
1484-
1485-void Logger::set_log_file(string const& path)
1486+ file_sink_->stop();
1487+ file_sink_->flush();
1488+ }
1489+}
1490+
1491+Logger::operator boost::log::sources::severity_channel_logger_mt<>&()
1492+{
1493+ return logger_; // No lock needed, immutable
1494+}
1495+
1496+src::severity_channel_logger_mt<>& Logger::operator()(Channel c)
1497+{
1498+ // No lock needed: channel_loggers_ is immutable, and the boolean is atomic.
1499+ return channel_loggers_[channel_names[c]].first;
1500+}
1501+
1502+bool Logger::set_channel(Channel c, bool enable)
1503+{
1504+ auto it = channel_loggers_.find(channel_names[c]);
1505+ assert(it != channel_loggers_.end());
1506+ bool was_enabled = it->second.second.exchange(enable);
1507+ return was_enabled;
1508+}
1509+
1510+bool Logger::set_channel(string channel_name, bool enable)
1511+{
1512+ auto it = channel_loggers_.find(channel_name);
1513+ if (it == channel_loggers_.end())
1514+ {
1515+ throw InvalidArgumentException("Logger::set_channel(): invalid channel name: " + channel_name);
1516+ }
1517+ bool was_enabled = it->second.second.exchange(enable);
1518+ return was_enabled;
1519+}
1520+
1521+void Logger::enable_channels(vector<string> const& names)
1522+{
1523+ exception_ptr ep;
1524+ for (auto&& name : names)
1525+ {
1526+ try
1527+ {
1528+ set_channel(name, true);
1529+ }
1530+ catch (InvalidArgumentException& e)
1531+ {
1532+ ep = ep ? make_exception_ptr(current_exception()) : e.remember(ep);
1533+ }
1534+ }
1535+ if (ep)
1536+ {
1537+ rethrow_exception(ep);
1538+ }
1539+}
1540+
1541+void Logger::set_log_file(string const& path, int rotation_size, int dir_size)
1542 {
1543 namespace ph = std::placeholders;
1544
1545 FileSinkPtr s = boost::make_shared<FileSinkT>(
1546- keywords::file_name = path + "_%N.log",
1547- keywords::rotation_size = 5 * 1024 * 1024,
1548- keywords::time_based_rotation = sinks::file::rotation_at_time_point(12, 0, 0));
1549- if (clog_sink_)
1550- {
1551- logging::core::get()->remove_sink(clog_sink_);
1552- }
1553- else
1554- {
1555- logging::core::get()->remove_sink(file_sink_);
1556- }
1557- file_sink_ = s;
1558+ keywords::file_name = path + "-%N.log",
1559+ keywords::rotation_size = rotation_size);
1560+
1561+ string parent = boost::filesystem::path(path).parent_path().native();
1562+ s->locked_backend()->set_file_collector(sinks::file::make_collector(keywords::target = parent,
1563+ keywords::max_size = dir_size));
1564+ s->locked_backend()->scan_for_files();
1565+
1566+ {
1567+ lock_guard<mutex> lock(mutex_);
1568+
1569+ if (clog_sink_)
1570+ {
1571+ logging::core::get()->remove_sink(clog_sink_);
1572+ clog_sink_ = nullptr;
1573+ }
1574+ else
1575+ {
1576+ logging::core::get()->remove_sink(file_sink_);
1577+ }
1578+
1579+ file_sink_ = s;
1580+ file_sink_->locked_backend()->auto_flush(true);
1581+ file_sink_->set_formatter(bind(&Logger::formatter, this, ph::_1, ph::_2));
1582+ logging::core::get()->add_sink(file_sink_);
1583+ }
1584 set_severity_threshold(severity_);
1585- file_sink_->set_formatter(std::bind(formatter, ph::_1, ph::_2, scope_id_));
1586- logging::core::get()->add_sink(s);
1587 }
1588
1589 Logger::Severity Logger::set_severity_threshold(Logger::Severity s)
1590 {
1591- auto old_s = severity_;
1592- severity_ = s;
1593- auto filter = expr::attr<string>("Channel") == to_string(reinterpret_cast<ptrdiff_t>(this))
1594- && expr::attr<int>("Severity") >= static_cast<int>(severity_);
1595+ auto old_s = severity_.exchange(s);
1596+
1597+ lock_guard<mutex> lock(mutex_);
1598+
1599+ auto filter = boost::phoenix::bind(&Logger::filter, this, severity.or_none(), channel.or_none());
1600 if (clog_sink_)
1601 {
1602 clog_sink_->set_filter(filter);
1603@@ -155,9 +218,40 @@
1604 {
1605 file_sink_->set_filter(filter);
1606 }
1607+
1608 return old_s;
1609 }
1610
1611+bool Logger::filter(logging::value_ref<int, tag::severity> const& level,
1612+ logging::value_ref<string, tag::channel> const& channel)
1613+{
1614+ if (level.get() < static_cast<int>(severity_)) // atomic
1615+ {
1616+ return false;
1617+ }
1618+ if (channel.get().empty())
1619+ {
1620+ return true;
1621+ }
1622+ // No lock needed: channel_loggers_ is immutable, and the boolean is atomic.
1623+ auto it = channel_loggers_.find(channel.get());
1624+ assert(it != channel_loggers_.end());
1625+ return it->second.second;
1626+}
1627+
1628+void Logger::formatter(logging::record_view const& rec,
1629+ logging::formatting_ostream& strm)
1630+{
1631+ string channel = expr::attr<string>("Channel")(rec).get();
1632+
1633+ string prefix = channel.empty() ? to_severity(expr::attr<int>("Severity")(rec).get()) : channel;
1634+
1635+ strm << "[" << expr::format_date_time<boost::posix_time::ptime>("TimeStamp", "%Y-%m-%d %H:%M:%S.%f")(rec) << "] "
1636+ << prefix << ": "
1637+ << scope_id_ << ": "
1638+ << rec[expr::smessage];
1639+}
1640+
1641 } // namespace internal
1642
1643 } // namespace scopes
1644
1645=== modified file 'src/scopes/internal/ObjectImpl.cpp'
1646--- src/scopes/internal/ObjectImpl.cpp 2014-11-20 07:06:57 +0000
1647+++ src/scopes/internal/ObjectImpl.cpp 2015-01-13 07:11:02 +0000
1648@@ -35,10 +35,8 @@
1649 namespace internal
1650 {
1651
1652-ObjectImpl::ObjectImpl(MWProxy const& mw_proxy, boost::log::sources::severity_channel_logger_mt<>& logger)
1653- : logger_(logger)
1654+ObjectImpl::ObjectImpl(MWProxy const& mw_proxy)
1655 {
1656- lock_guard<mutex> lock(proxy_mutex_); // TODO: Why this lock?
1657 mw_proxy_ = mw_proxy;
1658 }
1659
1660
1661=== modified file 'src/scopes/internal/PreviewQueryObject.cpp'
1662--- src/scopes/internal/PreviewQueryObject.cpp 2014-11-20 05:29:23 +0000
1663+++ src/scopes/internal/PreviewQueryObject.cpp 2015-01-13 07:11:02 +0000
1664@@ -16,10 +16,12 @@
1665 * Authored by: Michal Hruby <michal.hruby@canonical.com>
1666 */
1667
1668+#include <unity/scopes/internal/PreviewQueryObject.h>
1669+
1670 #include <unity/scopes/internal/MWQueryCtrl.h>
1671 #include <unity/scopes/internal/MWReply.h>
1672-#include <unity/scopes/internal/PreviewQueryObject.h>
1673 #include <unity/scopes/internal/PreviewReplyImpl.h>
1674+#include <unity/scopes/internal/RuntimeImpl.h>
1675 #include <unity/scopes/ListenerBase.h>
1676 #include <unity/scopes/PreviewReply.h>
1677 #include <unity/scopes/QueryBase.h>
1678@@ -41,9 +43,8 @@
1679
1680 PreviewQueryObject::PreviewQueryObject(std::shared_ptr<PreviewQueryBase> const& preview_base,
1681 MWReplyProxy const& reply,
1682- MWQueryCtrlProxy const& ctrl,
1683- boost::log::sources::severity_channel_logger_mt<>& logger)
1684- : QueryObject(preview_base, reply, ctrl, logger)
1685+ MWQueryCtrlProxy const& ctrl)
1686+ : QueryObject(preview_base, reply, ctrl)
1687 , preview_base_(preview_base)
1688 {
1689 assert(preview_base);
1690@@ -54,11 +55,11 @@
1691 // parent destructor will call ctrl_->destroy()
1692 }
1693
1694-void PreviewQueryObject::run(MWReplyProxy const& reply, InvokeInfo const& /* info */) noexcept
1695+void PreviewQueryObject::run(MWReplyProxy const& reply, InvokeInfo const& info) noexcept
1696 {
1697 assert(self_);
1698
1699- auto reply_proxy = make_shared<PreviewReplyImpl>(reply, self_, logger_);
1700+ auto reply_proxy = make_shared<PreviewReplyImpl>(reply, self_);
1701 assert(reply_proxy);
1702 reply_proxy_ = reply_proxy;
1703
1704@@ -78,12 +79,12 @@
1705 catch (std::exception const& e)
1706 {
1707 pushable_ = false;
1708- BOOST_LOG_SEV(logger_, Logger::Error) << "PreviewQueryObject::run(): " << e.what();
1709+ BOOST_LOG(info.mw->runtime()->logger()) << "PreviewQueryObject::run(): " << e.what();
1710 reply_->finished(CompletionDetails(CompletionDetails::Error, e.what())); // Oneway, can't block
1711 }
1712 catch (...)
1713 {
1714- BOOST_LOG_SEV(logger_, Logger::Error) << "PreviewQueryObject::run(): unknown exception";
1715+ BOOST_LOG(info.mw->runtime()->logger()) << "PreviewQueryObject::run(): unknown exception";
1716 reply_->finished(CompletionDetails(CompletionDetails::Error, "unknown exception")); // Oneway, can't block
1717 }
1718 }
1719
1720=== modified file 'src/scopes/internal/PreviewReplyImpl.cpp'
1721--- src/scopes/internal/PreviewReplyImpl.cpp 2014-11-20 05:29:23 +0000
1722+++ src/scopes/internal/PreviewReplyImpl.cpp 2015-01-13 07:11:02 +0000
1723@@ -34,11 +34,9 @@
1724 namespace internal
1725 {
1726
1727-PreviewReplyImpl::PreviewReplyImpl(MWReplyProxy const& mw_proxy,
1728- shared_ptr<QueryObjectBase> const& qo,
1729- boost::log::sources::severity_channel_logger_mt<>& logger)
1730- : ObjectImpl(mw_proxy, logger)
1731- , ReplyImpl(mw_proxy, qo, logger)
1732+PreviewReplyImpl::PreviewReplyImpl(MWReplyProxy const& mw_proxy, shared_ptr<QueryObjectBase> const& qo)
1733+ : ObjectImpl(mw_proxy)
1734+ , ReplyImpl(mw_proxy, qo)
1735 , layouts_push_disallowed_(false)
1736 {
1737 }
1738
1739=== modified file 'src/scopes/internal/QueryCtrlImpl.cpp'
1740--- src/scopes/internal/QueryCtrlImpl.cpp 2014-11-20 05:47:58 +0000
1741+++ src/scopes/internal/QueryCtrlImpl.cpp 2015-01-13 07:11:02 +0000
1742@@ -39,9 +39,8 @@
1743 {
1744
1745 QueryCtrlImpl::QueryCtrlImpl(MWQueryCtrlProxy const& ctrl_proxy,
1746- MWReplyProxy const& reply_proxy,
1747- boost::log::sources::severity_channel_logger_mt<>& logger)
1748- : ObjectImpl(ctrl_proxy, logger)
1749+ MWReplyProxy const& reply_proxy)
1750+ : ObjectImpl(ctrl_proxy)
1751 , reply_proxy_(reply_proxy)
1752 {
1753 // We remember the reply proxy so, when the query is cancelled, we can
1754@@ -82,7 +81,7 @@
1755 }
1756 catch (std::exception const& e)
1757 {
1758- BOOST_LOG_SEV(logger_, Logger::Error) << e.what();
1759+ BOOST_LOG(reply_proxy_->mw_base()->runtime()->logger()) << e.what();
1760 }
1761 }
1762
1763
1764=== modified file 'src/scopes/internal/QueryObject.cpp'
1765--- src/scopes/internal/QueryObject.cpp 2014-11-20 05:29:23 +0000
1766+++ src/scopes/internal/QueryObject.cpp 2015-01-13 07:11:02 +0000
1767@@ -22,9 +22,10 @@
1768 #include <unity/scopes/ActivationQueryBase.h>
1769 #include <unity/scopes/internal/MWQueryCtrl.h>
1770 #include <unity/scopes/internal/MWReply.h>
1771+#include <unity/scopes/internal/QueryBaseImpl.h>
1772 #include <unity/scopes/internal/QueryCtrlObject.h>
1773+#include <unity/scopes/internal/RuntimeImpl.h>
1774 #include <unity/scopes/internal/SearchReplyImpl.h>
1775-#include <unity/scopes/internal/QueryBaseImpl.h>
1776 #include <unity/scopes/PreviewQueryBase.h>
1777 #include <unity/scopes/QueryBase.h>
1778 #include <unity/scopes/SearchQueryBase.h>
1779@@ -45,23 +46,20 @@
1780
1781 QueryObject::QueryObject(std::shared_ptr<QueryBase> const& query_base,
1782 MWReplyProxy const& reply,
1783- MWQueryCtrlProxy const& ctrl,
1784- boost::log::sources::severity_channel_logger_mt<>& logger)
1785- : QueryObject(query_base, 0, reply, ctrl, logger)
1786+ MWQueryCtrlProxy const& ctrl)
1787+ : QueryObject(query_base, 0, reply, ctrl)
1788 {
1789 }
1790
1791 QueryObject::QueryObject(std::shared_ptr<QueryBase> const& query_base,
1792 int cardinality,
1793 MWReplyProxy const& reply,
1794- MWQueryCtrlProxy const& ctrl,
1795- boost::log::sources::severity_channel_logger_mt<>& logger)
1796+ MWQueryCtrlProxy const& ctrl)
1797 : query_base_(query_base)
1798 , reply_(reply)
1799 , ctrl_(ctrl)
1800 , pushable_(true)
1801 , cardinality_(cardinality)
1802- , logger_(logger)
1803 {
1804 }
1805
1806@@ -78,7 +76,7 @@
1807 }
1808 }
1809
1810-void QueryObject::run(MWReplyProxy const& reply, InvokeInfo const& /* info */) noexcept
1811+void QueryObject::run(MWReplyProxy const& reply, InvokeInfo const& info) noexcept
1812 {
1813 unique_lock<mutex> lock(mutex_);
1814
1815@@ -103,7 +101,11 @@
1816 // Create the reply proxy to pass to query_base_ and keep a weak_ptr, which we will need
1817 // if cancel() is called later.
1818 assert(self_);
1819- auto reply_proxy = make_shared<SearchReplyImpl>(reply, self_, cardinality_, search_query->department_id(), logger_);
1820+ auto reply_proxy = make_shared<SearchReplyImpl>(reply,
1821+ self_,
1822+ cardinality_,
1823+ search_query->query().query_string(),
1824+ search_query->department_id());
1825 assert(reply_proxy);
1826 reply_proxy_ = reply_proxy;
1827
1828@@ -123,13 +125,13 @@
1829 catch (std::exception const& e)
1830 {
1831 pushable_ = false;
1832- BOOST_LOG_SEV(logger_, Logger::Error) << "ScopeBase::run(): " << e.what();
1833+ BOOST_LOG(info.mw->runtime()->logger()) << "ScopeBase::run(): " << e.what();
1834 reply_->finished(CompletionDetails(CompletionDetails::Error, e.what())); // Oneway, can't block
1835 }
1836 catch (...)
1837 {
1838 pushable_ = false;
1839- BOOST_LOG_SEV(logger_, Logger::Error) << "ScopeBase::run(): unknown exception";
1840+ BOOST_LOG(info.mw->runtime()->logger()) << "ScopeBase::run(): unknown exception";
1841 reply_->finished(CompletionDetails(CompletionDetails::Error, "unknown exception")); // Oneway, can't block
1842 }
1843 }
1844
1845=== modified file 'src/scopes/internal/RegistryImpl.cpp'
1846--- src/scopes/internal/RegistryImpl.cpp 2014-11-20 05:29:23 +0000
1847+++ src/scopes/internal/RegistryImpl.cpp 2015-01-13 07:11:02 +0000
1848@@ -32,8 +32,8 @@
1849 namespace internal
1850 {
1851
1852-RegistryImpl::RegistryImpl(MWRegistryProxy const& mw_proxy, RuntimeImpl* runtime)
1853- : ObjectImpl(mw_proxy, runtime->logger())
1854+RegistryImpl::RegistryImpl(MWRegistryProxy const& mw_proxy)
1855+ : ObjectImpl(mw_proxy)
1856 {
1857 }
1858
1859
1860=== modified file 'src/scopes/internal/RegistryObject.cpp'
1861--- src/scopes/internal/RegistryObject.cpp 2014-12-08 13:27:57 +0000
1862+++ src/scopes/internal/RegistryObject.cpp 2015-01-13 07:11:02 +0000
1863@@ -92,8 +92,7 @@
1864 }
1865 catch (std::exception const& e)
1866 {
1867- BOOST_LOG_SEV(logger_, Logger::Error)
1868- << "RegistryObject(): failed to create registry publisher: " << e.what();
1869+ BOOST_LOG(logger_) << "RegistryObject(): failed to create registry publisher: " << e.what();
1870 }
1871 }
1872 }
1873@@ -122,8 +121,7 @@
1874 }
1875 catch(std::exception const& e)
1876 {
1877- BOOST_LOG_SEV(logger_, Logger::Error)
1878- << "RegistryObject::~RegistryObject(): " << e.what();
1879+ BOOST_LOG(logger_) << "RegistryObject::~RegistryObject(): " << e.what();
1880 }
1881 }
1882 }
1883@@ -157,8 +155,7 @@
1884 }
1885 catch (std::exception const& e)
1886 {
1887- BOOST_LOG_SEV(logger_, Logger::Error)
1888- << "cannot get metadata from remote registry: " << e.what();
1889+ BOOST_LOG(logger_) << "cannot get metadata from remote registry: " << e.what();
1890 }
1891 }
1892
1893@@ -186,8 +183,7 @@
1894 }
1895 catch (std::exception const& e)
1896 {
1897- BOOST_LOG_SEV(logger_, Logger::Error)
1898- << "cannot get scopes list from remote registry: " << e.what();
1899+ BOOST_LOG(logger_) << "cannot get scopes list from remote registry: " << e.what();
1900 }
1901 }
1902
1903@@ -382,7 +378,7 @@
1904 it->second->update_state(ScopeProcess::ProcessState::Stopping);
1905 break;
1906 default:
1907- BOOST_LOG_SEV(logger_, Logger::Error)
1908+ BOOST_LOG(logger_)
1909 << "RegistryObject::on_state_received(): unknown state received from scope: " << scope_id;
1910 }
1911 }
1912@@ -484,7 +480,7 @@
1913 }
1914 catch(std::exception const& e)
1915 {
1916- BOOST_LOG_SEV(logger_, Logger::Error) << "RegistryObject::ScopeProcess::~ScopeProcess(): " << e.what();
1917+ BOOST_LOG(logger_) << "RegistryObject::ScopeProcess::~ScopeProcess(): " << e.what();
1918 }
1919 }
1920
1921@@ -523,7 +519,7 @@
1922 {
1923 if (!wait_for_state(lock, ScopeProcess::Stopped))
1924 {
1925- BOOST_LOG_SEV(logger_, Logger::Error)
1926+ BOOST_LOG(logger_)
1927 << "RegistryObject::ScopeProcess::exec(): Force killing process. Scope: \""
1928 << exec_data_.scope_id << "\" did not stop after " << exec_data_.timeout_ms << " ms.";
1929 try
1930@@ -532,8 +528,7 @@
1931 }
1932 catch(std::exception const& e)
1933 {
1934- BOOST_LOG_SEV(logger_, Logger::Error)
1935- << "RegistryObject::ScopeProcess::exec(): kill() failed: " << e.what();
1936+ BOOST_LOG(logger_) << "RegistryObject::ScopeProcess::exec(): kill() failed: " << e.what();
1937 }
1938 }
1939 }
1940@@ -605,8 +600,7 @@
1941 }
1942 catch(std::exception const& e)
1943 {
1944- BOOST_LOG_SEV(logger_, Logger::Error)
1945- << "RegistryObject::ScopeProcess::exec(): kill() failed: " << e.what();
1946+ BOOST_LOG(logger_) << "RegistryObject::ScopeProcess::exec(): kill() failed: " << e.what();
1947 }
1948 throw unity::ResourceException("RegistryObject::ScopeProcess::exec(): exec aborted. Scope: \""
1949 + exec_data_.scope_id + "\" took longer than "
1950@@ -683,7 +677,7 @@
1951
1952 if (state_ != Stopping)
1953 {
1954- BOOST_LOG_SEV(logger_, Logger::Error)
1955+ BOOST_LOG(logger_)
1956 << "RegistryObject::ScopeProcess: Scope: \"" << exec_data_.scope_id
1957 << "\" closed unexpectedly. Either the process crashed or was killed forcefully.";
1958 }
1959@@ -696,7 +690,7 @@
1960 reg_publisher->send_message("stopped", exec_data_.scope_id);
1961 }
1962
1963- BOOST_LOG_SEV(logger_, Logger::Error)
1964+ BOOST_LOG(logger_)
1965 << "RegistryObject::ScopeProcess: Manually started process for scope: \""
1966 << exec_data_.scope_id << "\" exited";
1967
1968@@ -730,7 +724,7 @@
1969 {
1970 std::error_code ec;
1971
1972- BOOST_LOG_SEV(logger_, Logger::Error)
1973+ BOOST_LOG(logger_)
1974 << "RegistryObject::ScopeProcess::kill(): Scope: \"" << exec_data_.scope_id
1975 << "\" took longer than " << exec_data_.timeout_ms << " ms to exit gracefully. "
1976 << "Killing the process instead.";
1977@@ -744,7 +738,7 @@
1978 }
1979 catch (std::exception const&)
1980 {
1981- BOOST_LOG_SEV(logger_, Logger::Error)
1982+ BOOST_LOG(logger_)
1983 << "RegistryObject::ScopeProcess::kill(): Failed to kill scope: \"" << exec_data_.scope_id << "\"";
1984
1985 // clear the process handle
1986@@ -820,7 +814,7 @@
1987 started_message += " string:" + exec_data_.scope_id + " uint64:" + std::to_string(process_.pid());
1988 if (safe_system_call(started_message) != 0)
1989 {
1990- BOOST_LOG_SEV(logger_, Logger::Error)
1991+ BOOST_LOG(logger_)
1992 << "RegistryObject::ScopeProcess::publish_state_change(): "
1993 "Failed to execute SDK DBus ScopeLoaded callback "
1994 "(Scope ID: " << exec_data_.scope_id << ")";
1995@@ -841,7 +835,7 @@
1996 stopped_message += " string:" + exec_data_.scope_id;
1997 if (safe_system_call(stopped_message) != 0)
1998 {
1999- BOOST_LOG_SEV(logger_, Logger::Error)
2000+ BOOST_LOG(logger_)
2001 << "RegistryObject::ScopeProcess::publish_state_change(): "
2002 "Failed to execute SDK DBus ScopeStopped callback "
2003 "(Scope ID: " << exec_data_.scope_id << ")";
2004
2005=== modified file 'src/scopes/internal/ReplyImpl.cpp'
2006--- src/scopes/internal/ReplyImpl.cpp 2014-11-20 05:29:23 +0000
2007+++ src/scopes/internal/ReplyImpl.cpp 2015-01-13 07:11:02 +0000
2008@@ -38,10 +38,8 @@
2009 namespace internal
2010 {
2011
2012-ReplyImpl::ReplyImpl(MWReplyProxy const& mw_proxy,
2013- std::shared_ptr<QueryObjectBase> const& qo,
2014- boost::log::sources::severity_channel_logger_mt<>& logger)
2015- : ObjectImpl(mw_proxy, logger)
2016+ReplyImpl::ReplyImpl(MWReplyProxy const& mw_proxy, std::shared_ptr<QueryObjectBase> const& qo)
2017+ : ObjectImpl(mw_proxy)
2018 , qo_(qo)
2019 , finished_(false)
2020 {
2021@@ -94,7 +92,7 @@
2022 {
2023 fwd()->finished(CompletionDetails(CompletionDetails::OK)); // Oneway, can't block
2024 }
2025- catch (std::exception const& e)
2026+ catch (std::exception const&)
2027 {
2028 // No logging here because this may happen after the run time is destroyed.
2029 }
2030@@ -123,7 +121,7 @@
2031 {
2032 error_message = "unknown exception";
2033 }
2034- BOOST_LOG_SEV(logger_, Logger::Error) << "ReplyImpl::error(): " << error_message;
2035+ BOOST_LOG(mw_proxy_->mw_base()->runtime()->logger()) << "ReplyImpl::error(): " << error_message;
2036
2037 try
2038 {
2039@@ -131,7 +129,8 @@
2040 }
2041 catch (std::exception const& e)
2042 {
2043- BOOST_LOG_SEV(logger_, Logger::Error) << "ReplyImpl::error(): excpetion from finished(): " << error_message;
2044+ BOOST_LOG(mw_proxy_->mw_base()->runtime()->logger())
2045+ << "ReplyImpl::error(): excpetion from finished(): " << error_message;
2046 }
2047 }
2048
2049@@ -148,7 +147,8 @@
2050 }
2051 catch (std::exception const& e)
2052 {
2053- BOOST_LOG_SEV(logger_, Logger::Error) << "ReplyImpl::error(): excpetion from info(): " << e.what();
2054+ BOOST_LOG(mw_proxy_->mw_base()->runtime()->logger())
2055+ << "ReplyImpl::error(): excpetion from info(): " << e.what();
2056 }
2057 }
2058
2059
2060=== modified file 'src/scopes/internal/ReplyObject.cpp'
2061--- src/scopes/internal/ReplyObject.cpp 2014-11-18 07:04:04 +0000
2062+++ src/scopes/internal/ReplyObject.cpp 2015-01-13 07:11:02 +0000
2063@@ -183,11 +183,11 @@
2064 }
2065 catch (std::exception const& e)
2066 {
2067- BOOST_LOG_SEV(runtime_->logger(), Logger::Error) << "ReplyObject::finished(): " << e.what();
2068+ BOOST_LOG(runtime_->logger()) << "ReplyObject::finished(): " << e.what();
2069 }
2070 catch (...)
2071 {
2072- BOOST_LOG_SEV(runtime_->logger(), Logger::Error) << "ReplyObject::finished(): unknown exception";
2073+ BOOST_LOG(runtime_->logger()) << "ReplyObject::finished(): unknown exception";
2074 }
2075
2076 // Disconnect self from middleware, if this hasn't happened yet.
2077@@ -217,11 +217,11 @@
2078 }
2079 catch (std::exception const& e)
2080 {
2081- BOOST_LOG_SEV(runtime_->logger(), Logger::Error) << "ReplyObject::info(): " << e.what();
2082+ BOOST_LOG(runtime_->logger()) << "ReplyObject::info(): " << e.what();
2083 }
2084 catch (...)
2085 {
2086- BOOST_LOG_SEV(runtime_->logger(), Logger::Error) << "ReplyObject::info(): unknown exception";
2087+ BOOST_LOG(runtime_->logger()) << "ReplyObject::info(): unknown exception";
2088 }
2089 }
2090
2091
2092=== modified file 'src/scopes/internal/ResultReplyObject.cpp'
2093--- src/scopes/internal/ResultReplyObject.cpp 2014-08-12 09:04:49 +0000
2094+++ src/scopes/internal/ResultReplyObject.cpp 2015-01-13 07:11:02 +0000
2095@@ -17,7 +17,6 @@
2096 */
2097
2098 #include <unity/scopes/internal/ResultReplyObject.h>
2099-#include <unity/scopes/internal/RuntimeImpl.h>
2100 #include <unity/scopes/internal/AnnotationImpl.h>
2101 #include <unity/scopes/ListenerBase.h>
2102 #include <unity/scopes/Category.h>
2103@@ -43,6 +42,8 @@
2104 namespace internal
2105 {
2106
2107+class RuntimeImpl;
2108+
2109 ResultReplyObject::ResultReplyObject(SearchListenerBase::SPtr const& receiver, RuntimeImpl const* runtime,
2110 std::string const& scope_id, int cardinality, bool dont_reap) :
2111 ReplyObject(std::static_pointer_cast<ListenerBase>(receiver), runtime, scope_id, dont_reap),
2112
2113=== modified file 'src/scopes/internal/RuntimeConfig.cpp'
2114--- src/scopes/internal/RuntimeConfig.cpp 2014-11-13 00:28:01 +0000
2115+++ src/scopes/internal/RuntimeConfig.cpp 2015-01-13 07:11:02 +0000
2116@@ -19,8 +19,16 @@
2117 #include <unity/scopes/internal/RuntimeConfig.h>
2118
2119 #include <unity/scopes/internal/DfltConfig.h>
2120+#include <unity/scopes/ScopeExceptions.h>
2121+
2122+#include <boost/algorithm/string/classification.hpp>
2123+#include <boost/algorithm/string/constants.hpp>
2124+#include <boost/algorithm/string/split.hpp>
2125+#include <boost/filesystem.hpp>
2126 #include <unity/UnityExceptions.h>
2127
2128+#include <sys/stat.h>
2129+
2130 #include <stdlib.h>
2131
2132 using namespace std;
2133@@ -49,6 +57,10 @@
2134 const string cache_dir_key = "CacheDir";
2135 const string app_dir_key = "AppDir";
2136 const string config_dir_key = "ConfigDir";
2137+const string log_dir_key = "LogDir";
2138+const string max_log_file_size_key = "Log.MaxFileSize";
2139+const string max_log_dir_size_key = "Log.MaxDirSize";
2140+const string trace_channels_key = "Log.TraceChannels";
2141
2142 } // namespace
2143
2144@@ -65,16 +77,12 @@
2145 default_middleware_configfile_ = DFLT_ZMQ_MIDDLEWARE_INI;
2146 reap_expiry_ = DFLT_REAP_EXPIRY;
2147 reap_interval_ = DFLT_REAP_INTERVAL;
2148- try
2149- {
2150- cache_directory_ = default_cache_directory();
2151- app_directory_ = default_app_directory();
2152- config_directory_ = default_config_directory();
2153- }
2154- catch (ResourceException const& e)
2155- {
2156- throw_ex("Failed to get default data directory");
2157- }
2158+ max_log_file_size_ = DFLT_MAX_LOG_FILE_SIZE;
2159+ max_log_dir_size_ = DFLT_MAX_LOG_DIR_SIZE;
2160+ cache_directory_ = default_cache_directory();
2161+ app_directory_ = default_app_directory();
2162+ config_directory_ = default_config_directory();
2163+ log_directory_ = default_log_directory();
2164 }
2165 else
2166 {
2167@@ -96,6 +104,7 @@
2168 {
2169 throw_ex("Illegal value (" + to_string(reap_interval_) + ") for " + reap_interval_key + ": value must be > 0");
2170 }
2171+
2172 cache_directory_ = get_optional_string(runtime_config_group, cache_dir_key);
2173 if (cache_directory_.empty())
2174 {
2175@@ -105,9 +114,10 @@
2176 }
2177 catch (ResourceException const& e)
2178 {
2179- throw_ex("No CacheDir configured and failed to get default");
2180+ throw_ex("No " + cache_dir_key + " configured and failed to get default");
2181 }
2182 }
2183+
2184 app_directory_ = get_optional_string(runtime_config_group, app_dir_key);
2185 if (app_directory_.empty())
2186 {
2187@@ -117,9 +127,10 @@
2188 }
2189 catch (ResourceException const& e)
2190 {
2191- throw_ex("No AppDir configured and failed to get default");
2192+ throw_ex("No " + app_dir_key + " configured and failed to get default");
2193 }
2194 }
2195+
2196 config_directory_ = get_optional_string(runtime_config_group, config_dir_key);
2197 if (config_directory_.empty())
2198 {
2199@@ -129,8 +140,65 @@
2200 }
2201 catch (ResourceException const& e)
2202 {
2203- throw_ex("No ConfigDir configured and failed to get default");
2204- }
2205+ throw_ex("No " + config_dir_key + " configured and failed to get default");
2206+ }
2207+ }
2208+
2209+ try
2210+ {
2211+ // If explicitly set to the empty string, we succeed here.
2212+ log_directory_ = parser()->get_string(runtime_config_group, log_dir_key);
2213+ }
2214+ catch (LogicException const&)
2215+ {
2216+ // Use default value.
2217+ try
2218+ {
2219+ log_directory_ = default_log_directory();
2220+ }
2221+ catch (ResourceException const& e)
2222+ {
2223+ throw_ex("No " + log_dir_key + " configured and failed to get default");
2224+ }
2225+ }
2226+
2227+ // Check if we have an override for the log directory.
2228+ char const* logdir = getenv("UNITY_SCOPES_LOGDIR");
2229+ if (logdir)
2230+ {
2231+ log_directory_ = logdir;
2232+ }
2233+
2234+ max_log_file_size_ = get_optional_int(runtime_config_group, max_log_file_size_key, DFLT_MAX_LOG_FILE_SIZE);
2235+ if (max_log_file_size_ < 1024)
2236+ {
2237+ throw_ex("Illegal value (" + to_string(max_log_file_size_) + ") for " + max_log_file_size_key
2238+ + ": value must be > 1024");
2239+ }
2240+
2241+ max_log_dir_size_ = get_optional_int(runtime_config_group, max_log_dir_size_key, DFLT_MAX_LOG_DIR_SIZE);
2242+ if (max_log_dir_size_ <= max_log_file_size_)
2243+ {
2244+ throw_ex("Illegal value (" + to_string(max_log_dir_size_) + ") for " + max_log_dir_size_key
2245+ + ": value must be > " + max_log_file_size_key + " (" + to_string(max_log_file_size_) + ")");
2246+ }
2247+
2248+ try
2249+ {
2250+ trace_channels_ = parser()->get_string_array(runtime_config_group, trace_channels_key);
2251+ }
2252+ catch (LogicException const&)
2253+ {
2254+ // No TraceChannels configured.
2255+ }
2256+
2257+ // Check if we have an override for the trace channels.
2258+ char const* tc = getenv("UNITY_SCOPES_LOG_TRACECHANNELS");
2259+ if (tc && *tc != '\0')
2260+ {
2261+ vector<string> channels;
2262+ split(channels, tc, boost::is_any_of(";"), boost::token_compress_on);
2263+ trace_channels_ = channels;
2264 }
2265 }
2266
2267@@ -147,7 +215,11 @@
2268 reap_interval_key,
2269 cache_dir_key,
2270 app_dir_key,
2271- config_dir_key
2272+ config_dir_key,
2273+ log_dir_key,
2274+ max_log_file_size_key,
2275+ max_log_dir_size_key,
2276+ trace_channels_key
2277 }
2278 }
2279 };
2280@@ -213,6 +285,26 @@
2281 return config_directory_;
2282 }
2283
2284+string RuntimeConfig::log_directory() const
2285+{
2286+ return log_directory_;
2287+}
2288+
2289+int RuntimeConfig::max_log_file_size() const
2290+{
2291+ return max_log_file_size_;
2292+}
2293+
2294+int RuntimeConfig::max_log_dir_size() const
2295+{
2296+ return max_log_dir_size_;
2297+}
2298+
2299+vector<string> RuntimeConfig::trace_channels() const
2300+{
2301+ return trace_channels_;
2302+}
2303+
2304 string RuntimeConfig::default_cache_directory()
2305 {
2306 char const* home = getenv("HOME");
2307@@ -220,7 +312,7 @@
2308 {
2309 throw ResourceException("RuntimeConfig::default_cache_directory(): $HOME not set");
2310 }
2311- return string(home) + "/.local/share/unity-scopes";
2312+ return string(home) + "/" + DFLT_HOME_CACHE_SUBDIR;
2313 }
2314
2315 string RuntimeConfig::default_app_directory()
2316@@ -230,7 +322,7 @@
2317 {
2318 throw ResourceException("RuntimeConfig::default_app_directory(): $HOME not set");
2319 }
2320- return string(home) + "/.local/share";
2321+ return string(home) + "/" + DFLT_HOME_APP_SUBDIR;
2322 }
2323
2324 string RuntimeConfig::default_config_directory()
2325@@ -240,7 +332,22 @@
2326 {
2327 throw ResourceException("RuntimeConfig::default_config_directory(): $HOME not set");
2328 }
2329- return string(home) + "/.config/unity-scopes";
2330+ return string(home) + "/" + DFLT_HOME_CONFIG_SUBDIR;
2331+}
2332+
2333+string RuntimeConfig::default_log_directory()
2334+{
2335+ char const* home = getenv("HOME");
2336+ if (!home || *home == '\0')
2337+ {
2338+ throw ResourceException("RuntimeConfig::default_log_directory(): $HOME not set");
2339+ }
2340+ string dir = string(home) + "/" + DFLT_HOME_LOG_SUBDIR;
2341+
2342+ boost::system::error_code ec;
2343+ !boost::filesystem::exists(dir, ec) && ::mkdir(dir.c_str(), 0700);
2344+
2345+ return dir;
2346 }
2347
2348 } // namespace internal
2349
2350=== modified file 'src/scopes/internal/RuntimeImpl.cpp'
2351--- src/scopes/internal/RuntimeImpl.cpp 2014-12-04 04:33:50 +0000
2352+++ src/scopes/internal/RuntimeImpl.cpp 2015-01-13 07:11:02 +0000
2353@@ -59,15 +59,17 @@
2354 {
2355 try
2356 {
2357- lock_guard<mutex> lock(mutex_);
2358+ lock_guard<mutex> lock(mutex_); // TODO: shouldn't be necessary.
2359
2360 destroyed_ = false;
2361
2362 scope_id_ = scope_id;
2363+ string log_file_basename = scope_id;
2364 if (scope_id_.empty())
2365 {
2366 UniqueID id;
2367 scope_id_ = "c-" + id.gen();
2368+ log_file_basename = "client"; // Don't make lots of log files named like c-c4c758b100000000.
2369 }
2370
2371 // Until we know where the scope's cache directory is,
2372@@ -77,6 +79,28 @@
2373 // Create the middleware factory and get the registry identity and config filename.
2374 runtime_configfile_ = configfile;
2375 RuntimeConfig config(configfile);
2376+
2377+ // Configure trace channels.
2378+ try
2379+ {
2380+ logger_->enable_channels(config.trace_channels());
2381+ }
2382+ catch (...)
2383+ {
2384+ throw InvalidArgumentException("Runtime(): invalid trace channel name(s)");
2385+ }
2386+
2387+ // Now that we have the config, change the logger to log to a file.
2388+ // If log_dir was explicitly set to the empty string, continue
2389+ // logging to std::clog.
2390+ string log_dir = config.log_directory();
2391+ if (!log_dir.empty())
2392+ {
2393+ logger_->set_log_file(config.log_directory() + "/" + log_file_basename,
2394+ config.max_log_file_size(),
2395+ config.max_log_dir_size());
2396+ }
2397+
2398 string default_middleware = config.default_middleware();
2399 string middleware_configfile = config.default_middleware_configfile();
2400 middleware_factory_.reset(new MiddlewareFactory(this));
2401@@ -104,7 +128,7 @@
2402 // Create the registry proxy
2403 RegistryConfig reg_config(registry_identity_, registry_configfile_);
2404 auto registry_mw_proxy = middleware_->registry_proxy();
2405- registry_ = make_shared<RegistryImpl>(registry_mw_proxy, this);
2406+ registry_ = make_shared<RegistryImpl>(registry_mw_proxy);
2407 }
2408
2409 cache_dir_ = config.cache_directory();
2410@@ -117,7 +141,7 @@
2411 string msg = "Cannot instantiate run time for " + (scope_id.empty() ? "client" : scope_id) +
2412 ", config file: " + configfile;
2413 ConfigException ex(msg);
2414- BOOST_LOG_SEV(logger(), Logger::Error) << ex.what();
2415+ BOOST_LOG(logger()) << ex.what();
2416 throw ex;
2417 }
2418 }
2419@@ -130,11 +154,11 @@
2420 }
2421 catch (std::exception const& e) // LCOV_EXCL_LINE
2422 {
2423- BOOST_LOG_SEV(logger(), Logger::Error) << "~RuntimeImpl(): " << e.what();
2424+ BOOST_LOG(logger()) << "~RuntimeImpl(): " << e.what();
2425 }
2426 catch (...) // LCOV_EXCL_LINE
2427 {
2428- BOOST_LOG_SEV(logger(), Logger::Error) << "~RuntimeImpl(): unknown exception";
2429+ BOOST_LOG(logger()) << "~RuntimeImpl(): unknown exception";
2430 }
2431 }
2432
2433@@ -293,6 +317,11 @@
2434 return *logger_;
2435 }
2436
2437+boost::log::sources::severity_channel_logger_mt<>& RuntimeImpl::logger(Logger::Channel channel) const
2438+{
2439+ return (*logger_)(channel);
2440+}
2441+
2442 namespace
2443 {
2444
2445@@ -411,14 +440,13 @@
2446 // Check if this scope has requested debug mode, if so, disable the idle timeout
2447 ScopeConfig scope_config(scope_ini_file);
2448 int idle_timeout_ms = scope_config.debug_mode() ? -1 : scope_config.idle_timeout() * 1000;
2449- auto scope = unique_ptr<internal::ScopeObject>(new internal::ScopeObject(this,
2450- scope_base,
2451+ auto scope = unique_ptr<internal::ScopeObject>(new internal::ScopeObject(scope_base,
2452 scope_config.debug_mode()));
2453 mw->add_scope_object(scope_id_, move(scope), idle_timeout_ms);
2454 }
2455 else
2456 {
2457- auto scope = unique_ptr<internal::ScopeObject>(new internal::ScopeObject(this, scope_base));
2458+ auto scope = unique_ptr<internal::ScopeObject>(new internal::ScopeObject(scope_base));
2459 mw->add_scope_object(scope_id_, move(scope));
2460 }
2461
2462@@ -430,7 +458,7 @@
2463
2464 promise.set_value();
2465 mw->wait_for_shutdown();
2466- cleanup_scope.dealloc(); // Causes ScopeBase::run() to terminate if the scope is properly written
2467+ cleanup_scope.dealloc(); // Causes ScopeBase::run() to return if the scope is properly written
2468
2469 {
2470 // mw is now shut down, so we need a separate one to send the state update to the registry.
2471@@ -494,6 +522,16 @@
2472 }
2473 }
2474
2475+string RuntimeImpl::cache_directory() const
2476+{
2477+ return find_cache_dir();
2478+}
2479+
2480+string RuntimeImpl::tmp_directory() const
2481+{
2482+ return find_tmp_dir();
2483+}
2484+
2485 string RuntimeImpl::demangled_id() const
2486 {
2487 // For scopes that are in a click package together with an app,
2488
2489=== modified file 'src/scopes/internal/ScopeImpl.cpp'
2490--- src/scopes/internal/ScopeImpl.cpp 2014-11-20 05:29:23 +0000
2491+++ src/scopes/internal/ScopeImpl.cpp 2015-01-13 07:11:02 +0000
2492@@ -43,12 +43,12 @@
2493 namespace internal
2494 {
2495
2496-ScopeImpl::ScopeImpl(MWScopeProxy const& mw_proxy, RuntimeImpl* runtime, std::string const& scope_id) :
2497- ObjectImpl(mw_proxy, runtime->logger()),
2498- runtime_(runtime),
2499+ScopeImpl::ScopeImpl(MWScopeProxy const& mw_proxy, std::string const& scope_id) :
2500+ ObjectImpl(mw_proxy),
2501+ runtime_(mw_proxy->mw_base()->runtime()),
2502 scope_id_(scope_id)
2503 {
2504- assert(runtime);
2505+ assert(runtime_);
2506 }
2507
2508 ScopeImpl::~ScopeImpl()
2509@@ -99,7 +99,7 @@
2510 MWReplyProxy rp = fwd()->mw_base()->add_reply_object(ro);
2511
2512 // "Fake" QueryCtrlProxy that doesn't have a real MWQueryCtrlProxy yet.
2513- shared_ptr<QueryCtrlImpl> ctrl = make_shared<QueryCtrlImpl>(nullptr, rp, runtime_->logger());
2514+ shared_ptr<QueryCtrlImpl> ctrl = make_shared<QueryCtrlImpl>(nullptr, rp);
2515
2516 // We pass a shared pointer to the lambda (instead of the this pointer)
2517 // to keep ourselves alive until after the lambda fires.
2518@@ -152,7 +152,7 @@
2519 ReplyObject::SPtr ro(make_shared<ActivationReplyObject>(reply, runtime_, to_string(), fwd()->debug_mode()));
2520 MWReplyProxy rp = fwd()->mw_base()->add_reply_object(ro);
2521
2522- shared_ptr<QueryCtrlImpl> ctrl = make_shared<QueryCtrlImpl>(nullptr, rp, runtime_->logger());
2523+ shared_ptr<QueryCtrlImpl> ctrl = make_shared<QueryCtrlImpl>(nullptr, rp);
2524
2525 auto impl = dynamic_pointer_cast<ScopeImpl>(shared_from_this());
2526
2527@@ -200,7 +200,7 @@
2528 ReplyObject::SPtr ro(make_shared<ActivationReplyObject>(reply, runtime_, to_string(), fwd()->debug_mode()));
2529 MWReplyProxy rp = fwd()->mw_base()->add_reply_object(ro);
2530
2531- shared_ptr<QueryCtrlImpl> ctrl = make_shared<QueryCtrlImpl>(nullptr, rp, runtime_->logger());
2532+ shared_ptr<QueryCtrlImpl> ctrl = make_shared<QueryCtrlImpl>(nullptr, rp);
2533
2534 auto impl = dynamic_pointer_cast<ScopeImpl>(shared_from_this());
2535
2536@@ -249,7 +249,7 @@
2537 ReplyObject::SPtr ro(make_shared<PreviewReplyObject>(reply, runtime_, to_string(), fwd()->debug_mode()));
2538 MWReplyProxy rp = fwd()->mw_base()->add_reply_object(ro);
2539
2540- shared_ptr<QueryCtrlImpl> ctrl = make_shared<QueryCtrlImpl>(nullptr, rp, runtime_->logger());
2541+ shared_ptr<QueryCtrlImpl> ctrl = make_shared<QueryCtrlImpl>(nullptr, rp);
2542
2543 auto impl = dynamic_pointer_cast<ScopeImpl>(shared_from_this());
2544
2545@@ -283,9 +283,9 @@
2546 return ctrl;
2547 }
2548
2549-ScopeProxy ScopeImpl::create(MWScopeProxy const& mw_proxy, RuntimeImpl* runtime, std::string const& scope_id)
2550+ScopeProxy ScopeImpl::create(MWScopeProxy const& mw_proxy, std::string const& scope_id)
2551 {
2552- return make_shared<ScopeImpl>(mw_proxy, runtime, scope_id);
2553+ return make_shared<ScopeImpl>(mw_proxy, scope_id);
2554 }
2555
2556 MWScopeProxy ScopeImpl::fwd()
2557
2558=== modified file 'src/scopes/internal/ScopeMetadataImpl.cpp'
2559--- src/scopes/internal/ScopeMetadataImpl.cpp 2014-12-03 08:27:13 +0000
2560+++ src/scopes/internal/ScopeMetadataImpl.cpp 2015-01-13 07:11:02 +0000
2561@@ -499,7 +499,7 @@
2562 auto endpoint = it2->second.get_string();
2563 throw_on_empty("proxy.endpoint", endpoint);
2564 auto mw_proxy = mw_->create_scope_proxy(identity, endpoint);
2565- proxy_ = ScopeImpl::create(mw_proxy, mw_->runtime(), scope_id_);
2566+ proxy_ = ScopeImpl::create(mw_proxy, scope_id_);
2567
2568 it = find_or_throw(var, "display_name");
2569 display_name_ = it->second.get_string();
2570
2571=== modified file 'src/scopes/internal/ScopeObject.cpp'
2572--- src/scopes/internal/ScopeObject.cpp 2014-11-18 07:04:04 +0000
2573+++ src/scopes/internal/ScopeObject.cpp 2015-01-13 07:11:02 +0000
2574@@ -46,12 +46,10 @@
2575 namespace internal
2576 {
2577
2578-ScopeObject::ScopeObject(RuntimeImpl* runtime, ScopeBase* scope_base, bool debug_mode) :
2579- runtime_(runtime),
2580+ScopeObject::ScopeObject(ScopeBase* scope_base, bool debug_mode) :
2581 scope_base_(scope_base),
2582 debug_mode_(debug_mode)
2583 {
2584- assert(runtime);
2585 assert(scope_base);
2586 }
2587
2588@@ -70,7 +68,7 @@
2589 // to be safe, we don't assert, in case someone is running a broken client.
2590
2591 // TODO: log error about incoming request containing an invalid reply proxy.
2592- throw LogicException("Scope \"" + runtime_->scope_id() + "\": query() called with null reply proxy");
2593+ throw LogicException("Scope \"" + mw_base->runtime()->scope_id() + "\": query() called with null reply proxy");
2594 }
2595
2596 // Ask scope to instantiate a new query.
2597@@ -80,16 +78,16 @@
2598 query_base = query_factory_fun();
2599 if (!query_base)
2600 {
2601- string msg = "Scope \"" + runtime_->scope_id() + "\" returned nullptr from query_factory_fun()";
2602- BOOST_LOG_SEV(runtime_->logger(), Logger::Error) << msg;
2603+ string msg = "Scope \"" + mw_base->runtime()->scope_id() + "\" returned nullptr from query_factory_fun()";
2604+ BOOST_LOG(mw_base->runtime()->logger()) << msg;
2605 throw ResourceException(msg);
2606 }
2607 query_base->p->set_settings_db(scope_base_->p->settings_db());
2608 }
2609 catch (...)
2610 {
2611- string msg = "Scope \"" + runtime_->scope_id() + "\" threw an exception from query_factory_fun()";
2612- BOOST_LOG_SEV(runtime_->logger(), Logger::Error) << msg;
2613+ string msg = "Scope \"" + mw_base->runtime()->scope_id() + "\" threw an exception from query_factory_fun()";
2614+ BOOST_LOG(mw_base->runtime()->logger()) << msg;
2615 throw ResourceException(msg);
2616 }
2617
2618@@ -127,8 +125,7 @@
2619 catch (...)
2620 {
2621 }
2622- BOOST_LOG_SEV(runtime_->logger(), Logger::Error)
2623- << "ScopeObject::query(): " << e.what();
2624+ BOOST_LOG(mw_base->runtime()->logger()) << "ScopeObject::query(): " << e.what();
2625 throw;
2626 }
2627 catch (...)
2628@@ -140,8 +137,7 @@
2629 catch (...)
2630 {
2631 }
2632- BOOST_LOG_SEV(runtime_->logger(), Logger::Error)
2633- << "ScopeObject::query(): unknown exception";
2634+ BOOST_LOG(mw_base->runtime()->logger()) << "ScopeObject::query(): unknown exception";
2635 throw;
2636 }
2637 return ctrl_proxy;
2638@@ -159,7 +155,7 @@
2639 return search_query;
2640 },
2641 [&reply, &hints, this](QueryBase::SPtr query_base, MWQueryCtrlProxy ctrl_proxy) -> QueryObjectBase::SPtr {
2642- return make_shared<QueryObject>(query_base, hints.cardinality(), reply, ctrl_proxy, runtime_->logger());
2643+ return make_shared<QueryObject>(query_base, hints.cardinality(), reply, ctrl_proxy);
2644 }
2645 );
2646 }
2647@@ -176,7 +172,7 @@
2648 [&reply, this](QueryBase::SPtr query_base, MWQueryCtrlProxy ctrl_proxy) -> QueryObjectBase::SPtr {
2649 auto activation_base = dynamic_pointer_cast<ActivationQueryBase>(query_base);
2650 assert(activation_base);
2651- return make_shared<ActivationQueryObject>(activation_base, reply, ctrl_proxy, runtime_->logger());
2652+ return make_shared<ActivationQueryObject>(activation_base, reply, ctrl_proxy);
2653 }
2654 );
2655 }
2656@@ -195,7 +191,7 @@
2657 [&reply, this](QueryBase::SPtr query_base, MWQueryCtrlProxy ctrl_proxy) -> QueryObjectBase::SPtr {
2658 auto activation_base = dynamic_pointer_cast<ActivationQueryBase>(query_base);
2659 assert(activation_base);
2660- return make_shared<ActivationQueryObject>(activation_base, reply, ctrl_proxy, runtime_->logger());
2661+ return make_shared<ActivationQueryObject>(activation_base, reply, ctrl_proxy);
2662 }
2663 );
2664 }
2665@@ -212,7 +208,7 @@
2666 [&reply, this](QueryBase::SPtr query_base, MWQueryCtrlProxy ctrl_proxy) -> QueryObjectBase::SPtr {
2667 auto preview_query = dynamic_pointer_cast<PreviewQueryBase>(query_base);
2668 assert(preview_query);
2669- return make_shared<PreviewQueryObject>(preview_query, reply, ctrl_proxy, runtime_->logger());
2670+ return make_shared<PreviewQueryObject>(preview_query, reply, ctrl_proxy);
2671 }
2672 );
2673 }
2674
2675=== modified file 'src/scopes/internal/SearchReplyImpl.cpp'
2676--- src/scopes/internal/SearchReplyImpl.cpp 2014-11-20 05:29:23 +0000
2677+++ src/scopes/internal/SearchReplyImpl.cpp 2015-01-13 07:11:02 +0000
2678@@ -20,12 +20,17 @@
2679 #include <unity/scopes/internal/SearchReplyImpl.h>
2680
2681 #include <unity/scopes/Annotation.h>
2682-#include <unity/scopes/CategorisedResult.h>
2683+#include <unity/scopes/internal/CategorisedResultImpl.h>
2684 #include <unity/scopes/internal/DepartmentImpl.h>
2685+#include <unity/scopes/internal/FilterBaseImpl.h>
2686 #include <unity/scopes/internal/MWReply.h>
2687-#include <unity/scopes/internal/FilterBaseImpl.h>
2688 #include <unity/scopes/internal/QueryObjectBase.h>
2689+#include <unity/scopes/internal/RuntimeImpl.h>
2690+#include <unity/scopes/ScopeExceptions.h>
2691 #include <unity/UnityExceptions.h>
2692+#include <unity/util/FileIO.h>
2693+
2694+#include <stdlib.h>
2695
2696 using namespace std;
2697
2698@@ -39,21 +44,24 @@
2699 {
2700
2701 SearchReplyImpl::SearchReplyImpl(MWReplyProxy const& mw_proxy,
2702- std::shared_ptr<QueryObjectBase> const& qo,
2703+ shared_ptr<QueryObjectBase> const& qo,
2704 int cardinality,
2705- std::string const& current_department_id,
2706- boost::log::sources::severity_channel_logger_mt<>& logger)
2707- : ObjectImpl(mw_proxy, logger)
2708- , ReplyImpl(mw_proxy, qo, logger)
2709+ string const& query_string,
2710+ string const& current_department_id)
2711+ : ObjectImpl(mw_proxy)
2712+ , ReplyImpl(mw_proxy, qo)
2713 , cat_registry_(new CategoryRegistry())
2714 , cardinality_(cardinality)
2715 , num_pushes_(0)
2716+ , finished_(false)
2717+ , query_string_(query_string)
2718 , current_department_(current_department_id)
2719 {
2720 }
2721
2722 SearchReplyImpl::~SearchReplyImpl()
2723 {
2724+ finished();
2725 }
2726
2727 void SearchReplyImpl::register_departments(Department::SCPtr const& parent)
2728@@ -68,6 +76,12 @@
2729 throw unity::LogicException("SearchReplyImpl::register_departments(): Failed to validate departments");
2730 }
2731
2732+ if (query_string_.empty())
2733+ {
2734+ lock_guard<mutex> lock(mutex_);
2735+ cached_departments_ = parent;
2736+ }
2737+
2738 ReplyImpl::push(internal::DepartmentImpl::serialize_departments(parent)); // ignore return value?
2739 }
2740
2741@@ -77,10 +91,10 @@
2742 push(category);
2743 }
2744
2745-Category::SCPtr SearchReplyImpl::register_category(std::string const& id,
2746- std::string const& title,
2747- std::string const &icon,
2748- CategoryRenderer const& renderer_template)
2749+Category::SCPtr SearchReplyImpl::register_category(string const& id,
2750+ string const& title,
2751+ string const &icon,
2752+ CategoryRenderer const& renderer_template)
2753 {
2754 // will throw if adding same category again
2755 auto cat = cat_registry_->register_category(id, title, icon, nullptr, renderer_template);
2756@@ -88,11 +102,11 @@
2757 return cat;
2758 }
2759
2760-Category::SCPtr SearchReplyImpl::register_category(std::string const& id,
2761- std::string const& title,
2762- std::string const& icon,
2763- CannedQuery const& query,
2764- CategoryRenderer const& renderer_template)
2765+Category::SCPtr SearchReplyImpl::register_category(string const& id,
2766+ string const& title,
2767+ string const& icon,
2768+ CannedQuery const& query,
2769+ CategoryRenderer const& renderer_template)
2770 {
2771 // will throw if adding same category again
2772 auto cat = cat_registry_->register_category(id, title, icon, make_shared<CannedQuery>(query), renderer_template);
2773@@ -100,7 +114,7 @@
2774 return cat;
2775 }
2776
2777-Category::SCPtr SearchReplyImpl::lookup_category(std::string const& id)
2778+Category::SCPtr SearchReplyImpl::lookup_category(string const& id)
2779 {
2780 return cat_registry_->lookup_category(id);
2781 }
2782@@ -128,6 +142,14 @@
2783 return false;
2784 }
2785
2786+ // We cache the results of surfacing queries so, if a scope has not connectivity,
2787+ // we can replay the results of the last successful surfacing query.
2788+ if (query_string_.empty())
2789+ {
2790+ lock_guard<mutex> lock(mutex_);
2791+ cached_results_.push_back(result);
2792+ }
2793+
2794 // Enforce cardinality limit (0 means no limit). If the scope pushes more results
2795 // than requested, future pushes are ignored. push() returns false
2796 // on the last call that actually still pushed a result.
2797@@ -167,6 +189,201 @@
2798 return ReplyImpl::push(var);
2799 }
2800
2801+void SearchReplyImpl::finished()
2802+{
2803+ if (finished_.exchange(true))
2804+ {
2805+ return;
2806+ }
2807+ write_cached_results();
2808+ ReplyImpl::finished(); // Upcall to deal with the normal case
2809+}
2810+
2811+static constexpr char const* cache_file_name = ".surfacing_cache";
2812+
2813+void SearchReplyImpl::write_cached_results() noexcept
2814+{
2815+ assert(finished_);
2816+
2817+ if (!query_string_.empty())
2818+ {
2819+ return; // Caching applies only to surfacing queries
2820+ }
2821+
2822+ string tmp_path;
2823+ try
2824+ {
2825+ // Open a temporary file for writing.
2826+ tmp_path = mw_proxy_->mw_base()->runtime()->cache_directory() + "/" + cache_file_name + "XXXXXX";
2827+ auto opener = [tmp_path]()
2828+ {
2829+ int tmp_fd = mkstemp(const_cast<char*>(tmp_path.c_str()));
2830+ if (tmp_fd == -1)
2831+ {
2832+ throw FileException("cannot open tmp file " + tmp_path, errno);
2833+ }
2834+ return tmp_fd;
2835+ };
2836+ auto closer = [tmp_path](int fd)
2837+ {
2838+ if (::close(fd) == -1)
2839+ {
2840+ // LCOV_EXCL_START
2841+ throw FileException("cannot close tmp file " + tmp_path + " (fd = " + std::to_string(fd) + ")", errno);
2842+ // LCOV_EXCL_STOP
2843+ }
2844+ };
2845+ unity::util::ResourcePtr<int, decltype(closer)> tmp_file(opener(), closer);
2846+
2847+ // Turn departments, categories, and results into a JSON string.
2848+ VariantMap departments;
2849+ if (cached_departments_)
2850+ {
2851+ departments = cached_departments_->serialize();
2852+ }
2853+ VariantArray categories = cat_registry_->serialize();
2854+ VariantArray results;
2855+ for (auto const& r : cached_results_)
2856+ {
2857+ results.push_back(Variant(r.serialize()));
2858+ }
2859+ VariantMap vm;
2860+ vm["departments"] = move(departments);
2861+ vm["categories"] = move(categories);
2862+ vm["results"] = move(results);
2863+ string const json = Variant(move(vm)).serialize_json();
2864+
2865+ // Write tmp file.
2866+ if (::write(tmp_file.get(), json.c_str(), json.size()) != static_cast<int>(json.size()))
2867+ {
2868+ // LCOV_EXCL_START
2869+ throw FileException("cannot write tmp file " + tmp_path + " (fd = " + std::to_string(tmp_file.get()) + ")",
2870+ errno);
2871+ // LCOV_EXCL_STOP
2872+ }
2873+ tmp_file.dealloc(); // Close tmp file.
2874+
2875+ // Atomically replace the old cache with the new one.
2876+ string cache_path = mw_proxy_->mw_base()->runtime()->cache_directory() + "/" + cache_file_name;
2877+ if (rename(tmp_path.c_str(), cache_path.c_str()) == -1)
2878+ {
2879+ throw FileException("cannot rename tmp file " + tmp_path + " to " + cache_path, errno); // LCOV_EXCL_LINE
2880+ }
2881+ }
2882+ catch (std::exception const& e)
2883+ {
2884+ ::unlink(tmp_path.c_str());
2885+ BOOST_LOG(mw_proxy_->mw_base()->runtime()->logger())
2886+ << "SearchReply::write_cached_results(): " << e.what();
2887+ }
2888+ // LCOV_EXCL_START
2889+ catch (...)
2890+ {
2891+ ::unlink(tmp_path.c_str());
2892+ BOOST_LOG(mw_proxy_->mw_base()->runtime()->logger())
2893+ << "SearchReply::write_cached_results(): unknown exception";
2894+ }
2895+ // LCOV_EXCL_STOP
2896+}
2897+
2898+void SearchReplyImpl::push_surfacing_results_from_cache() noexcept
2899+{
2900+ if (!query_string_.empty())
2901+ {
2902+ return; // Caching applies only to surfacing queries
2903+ }
2904+
2905+ if (finished_.exchange(true))
2906+ {
2907+ return;
2908+ }
2909+
2910+ string cache_path = mw_proxy_->mw_base()->runtime()->cache_directory() + "/" + cache_file_name;
2911+ try
2912+ {
2913+ // Read cache file.
2914+ string json;
2915+ try
2916+ {
2917+ json = unity::util::read_text_file(cache_path);
2918+ }
2919+ catch (unity::FileException const& e)
2920+ {
2921+ if (e.error() == ENOENT)
2922+ {
2923+ ReplyImpl::finished();
2924+ return; // No cache has been written yet.
2925+ }
2926+ throw;
2927+ }
2928+
2929+ // Decode JSON for the three sections.
2930+ Variant v(Variant::deserialize_json(json));
2931+ VariantMap vm = v.get_dict();
2932+
2933+ auto it = vm.find("departments");
2934+ if (it == vm.end())
2935+ {
2936+ throw unity::scopes::NotFoundException("malformed cache file", "departments");
2937+ }
2938+ auto department_dict = it->second.get_dict();
2939+
2940+ it = vm.find("categories");
2941+ if (it == vm.end())
2942+ {
2943+ throw unity::scopes::NotFoundException("malformed cache file", "categories");
2944+ }
2945+ auto category_array = it->second.get_array();
2946+
2947+ it = vm.find("results");
2948+ if (it == vm.end())
2949+ {
2950+ throw unity::scopes::NotFoundException("malformed cache file", "results");
2951+ }
2952+ auto result_array = it->second.get_array();
2953+
2954+ // We have the JSON strings as Variants, re-create the native representations
2955+ // and re-instate them.
2956+ if (!department_dict.empty())
2957+ {
2958+ auto departments = DepartmentImpl::create(department_dict);
2959+ register_departments(move(departments));
2960+ }
2961+
2962+ for (auto const& c : category_array)
2963+ {
2964+ // Can't use make_shared here because that isn't a friend of Category.
2965+ auto cp = Category::SCPtr(new Category(c.get_dict()));
2966+ register_category(cp);
2967+ }
2968+
2969+ for (auto const& r : result_array)
2970+ {
2971+ VariantMap dict = r.get_dict();
2972+ string const cat_id = dict.at("internal").get_dict().at("cat_id").get_string();
2973+ auto cat = lookup_category(cat_id);
2974+ auto crip = new CategorisedResultImpl(move(cat), move(dict));
2975+ auto cr = CategorisedResult(crip);
2976+ push(cr);
2977+ }
2978+ }
2979+ catch (std::exception const& e)
2980+ {
2981+ BOOST_LOG(mw_proxy_->mw_base()->runtime()->logger())
2982+ << "SearchReply::push_surfacing_results_from_cache() (file = " + cache_path + "): " << e.what();
2983+ }
2984+ // LCOV_EXCL_START
2985+ catch (...)
2986+ {
2987+ BOOST_LOG(mw_proxy_->mw_base()->runtime()->logger())
2988+ << "SearchReply::push_surfacing_results_from_cache() (file = " + cache_path + "): unknown exception";
2989+ }
2990+ // LCOV_EXCL_STOP
2991+
2992+ // Query is complete.
2993+ ReplyImpl::finished();
2994+}
2995+
2996 } // namespace internal
2997
2998 } // namespace scopes
2999
3000=== modified file 'src/scopes/internal/SettingsDB.cpp'
3001--- src/scopes/internal/SettingsDB.cpp 2014-12-02 04:18:44 +0000
3002+++ src/scopes/internal/SettingsDB.cpp 2015-01-13 07:11:02 +0000
3003@@ -184,8 +184,6 @@
3004 #pragma GCC diagnostic pop
3005
3006 int bytes_avail = 0;
3007- static_assert(std::alignment_of<char*>::value >= std::alignment_of<struct inotify_event>::value,
3008- "cannot use std::string as buffer for inotify events");
3009 string buffer;
3010
3011 // Poll for notifications until stop is requested
3012@@ -230,7 +228,12 @@
3013 int i = 0;
3014 while (i < bytes_read)
3015 {
3016+ static_assert(std::alignment_of<char*>::value >= std::alignment_of<struct inotify_event>::value,
3017+ "cannot use std::string as buffer for inotify events");
3018+#pragma GCC diagnostic push
3019+#pragma GCC diagnostic ignored "-Wcast-align"
3020 auto event = reinterpret_cast<inotify_event const*>(&buffer[i]);
3021+#pragma GCC diagnostic pop
3022
3023 if (event->mask & IN_DELETE_SELF)
3024 {
3025@@ -262,13 +265,13 @@
3026 }
3027 catch (exception const& e)
3028 {
3029- BOOST_LOG_SEV(logger_, Logger::Error) << "SettingsDB::watch_thread(): Thread aborted: " << e.what();
3030+ BOOST_LOG(logger_) << "SettingsDB::watch_thread(): Thread aborted: " << e.what();
3031 lock_guard<mutex> lock(mutex_);
3032 thread_state_ = Failed;
3033 }
3034 catch (...)
3035 {
3036- BOOST_LOG_SEV(logger_, Logger::Error) << "SettingsDB::watch_thread(): Thread aborted: unknown exception";
3037+ BOOST_LOG(logger_) << "SettingsDB::watch_thread(): Thread aborted: unknown exception";
3038 lock_guard<mutex> lock(mutex_);
3039 thread_state_ = Failed;
3040 }
3041@@ -337,9 +340,9 @@
3042 | IN_DELETE_SELF));
3043 if (watch_.get() < 0)
3044 {
3045- throw ResourceException("SettingsDB::add_watch(): failed to add watch for path: \"" +
3046- db_path_ + "\". inotify_add_watch() failed. (fd = " +
3047- to_string(fd_.get()) + ", path = " + db_path_ + ")");
3048+ throw SyscallException("SettingsDB::add_watch(): failed to add watch for path: \"" +
3049+ db_path_ + "\". inotify_add_watch() failed. (fd = " +
3050+ to_string(fd_.get()) + ", path = " + db_path_ + ")", errno);
3051 }
3052
3053 state_changed_ = true;
3054
3055=== modified file 'src/scopes/internal/smartscopes/SSQueryObject.cpp'
3056--- src/scopes/internal/smartscopes/SSQueryObject.cpp 2014-11-20 05:29:23 +0000
3057+++ src/scopes/internal/smartscopes/SSQueryObject.cpp 2015-01-13 07:11:02 +0000
3058@@ -19,8 +19,10 @@
3059 #include <unity/scopes/internal/smartscopes/SSQueryObject.h>
3060
3061 #include <unity/scopes/ActivationQueryBase.h>
3062+#include <unity/scopes/internal/InvokeInfo.h>
3063 #include <unity/scopes/internal/MWReply.h>
3064 #include <unity/scopes/internal/PreviewReplyImpl.h>
3065+#include <unity/scopes/internal/RuntimeImpl.h>
3066 #include <unity/scopes/internal/SearchReplyImpl.h>
3067 #include <unity/scopes/PreviewQueryBase.h>
3068 #include <unity/scopes/PreviewReply.h>
3069@@ -46,8 +48,7 @@
3070 namespace smartscopes
3071 {
3072
3073-SSQueryObject::SSQueryObject(boost::log::sources::severity_channel_logger_mt<>& logger)
3074- : logger_(logger)
3075+SSQueryObject::SSQueryObject()
3076 {
3077 }
3078
3079@@ -55,7 +56,7 @@
3080 {
3081 }
3082
3083-void SSQueryObject::run(MWReplyProxy const& reply, InvokeInfo const& /*info*/) noexcept
3084+void SSQueryObject::run(MWReplyProxy const& reply, InvokeInfo const& info) noexcept
3085 {
3086 decltype(queries_.begin()) query_it;
3087
3088@@ -94,7 +95,7 @@
3089 std::lock_guard<std::mutex> lock(queries_mutex_);
3090
3091 query_it->second->q_pushable = false;
3092- BOOST_LOG_SEV(logger_, Logger::Error) << "SSQueryObject::run(): " << e.what();
3093+ BOOST_LOG(info.mw->runtime()->logger()) << "SSQueryObject::run(): " << e.what();
3094 reply->finished(CompletionDetails(CompletionDetails::Error, e.what())); // Oneway, can't block
3095 }
3096 catch (...)
3097@@ -102,7 +103,7 @@
3098 std::lock_guard<std::mutex> lock(queries_mutex_);
3099
3100 query_it->second->q_pushable = false;
3101- BOOST_LOG_SEV(logger_, Logger::Error) << "SSQueryObject::run(): unknown exception";
3102+ BOOST_LOG(info.mw->runtime()->logger()) << "SSQueryObject::run(): unknown exception";
3103 reply->finished(CompletionDetails(CompletionDetails::Error, "unknown exception")); // Oneway, can't block
3104 }
3105
3106@@ -206,8 +207,8 @@
3107 q_reply_proxy = make_shared<SearchReplyImpl>(reply,
3108 shared_from_this(),
3109 query->q_cardinality,
3110- q_base->department_id(),
3111- logger_);
3112+ q_base->query().query_string(),
3113+ q_base->department_id());
3114 assert(q_reply_proxy);
3115 query->q_reply_proxy = q_reply_proxy;
3116
3117@@ -229,7 +230,7 @@
3118
3119 // Create the reply proxy and keep a weak_ptr, which we will need
3120 // if cancel() is called later.
3121- q_reply_proxy = make_shared<PreviewReplyImpl>(reply, shared_from_this(), logger_);
3122+ q_reply_proxy = make_shared<PreviewReplyImpl>(reply, shared_from_this());
3123 assert(q_reply_proxy);
3124 query->q_reply_proxy = q_reply_proxy;
3125
3126
3127=== modified file 'src/scopes/internal/smartscopes/SSRegistryObject.cpp'
3128--- src/scopes/internal/smartscopes/SSRegistryObject.cpp 2014-12-03 06:53:40 +0000
3129+++ src/scopes/internal/smartscopes/SSRegistryObject.cpp 2015-01-13 07:11:02 +0000
3130@@ -50,7 +50,7 @@
3131 : ssclient_(std::make_shared<SmartScopesClient>(
3132 std::make_shared<HttpClientQt>(ss_config.http_reply_timeout() * 1000), // need millisecs
3133 std::make_shared<JsonCppNode>(),
3134- middleware->runtime()->logger(),
3135+ middleware->runtime(),
3136 sss_url))
3137 , refresh_stopped_(false)
3138 , middleware_(middleware)
3139@@ -82,8 +82,7 @@
3140 catch (std::exception const& e)
3141 {
3142
3143- BOOST_LOG_SEV(middleware_->runtime()->logger(), Logger::Error)
3144- << "SSRegistryObject: get_remote_scopes() failed: " << e.what();
3145+ BOOST_LOG(middleware_->runtime()->logger()) << "SSRegistryObject: get_remote_scopes() failed: " << e.what();
3146 }
3147
3148 refresh_thread_ = std::thread(&SSRegistryObject::refresh_thread, this);
3149@@ -96,7 +95,7 @@
3150 }
3151 catch (std::exception const& e)
3152 {
3153- BOOST_LOG_SEV(middleware_->runtime()->logger(), Logger::Error)
3154+ BOOST_LOG(middleware_->runtime()->logger())
3155 << "SSRegistryObject(): failed to create registry publisher: " << e.what();
3156 }
3157 }
3158@@ -210,7 +209,7 @@
3159 }
3160 catch (std::exception const& e)
3161 {
3162- BOOST_LOG_SEV(middleware_->runtime()->logger(), Logger::Error)
3163+ BOOST_LOG(middleware_->runtime()->logger())
3164 << "SSRegistryObject: get_remote_scopes() failed: " << e.what();
3165 }
3166 }
3167@@ -284,7 +283,7 @@
3168 }
3169 catch (ResourceException const& e)
3170 {
3171- BOOST_LOG_SEV(middleware_->runtime()->logger(), Logger::Error)
3172+ BOOST_LOG(middleware_->runtime()->logger())
3173 << "SSRegistryObject: ignoring invalid settings JSON for scope \"" << scope.id << "\": "
3174 << e.what();
3175 }
3176@@ -333,7 +332,7 @@
3177 }
3178 catch (ResourceException const& e)
3179 {
3180- BOOST_LOG_SEV(middleware_->runtime()->logger(), Logger::Error)
3181+ BOOST_LOG(middleware_->runtime()->logger())
3182 << "SSRegistryObject: ignoring invalid settings JSON for scope \"" << scope.id << "\": "
3183 << e.what();
3184 }
3185@@ -348,7 +347,6 @@
3186 metadata->set_keywords(scope.keywords);
3187
3188 ScopeProxy proxy = ScopeImpl::create(middleware_->create_scope_proxy(scope.id, ss_scope_endpoint_),
3189- middleware_->runtime(),
3190 scope.id);
3191
3192 metadata->set_proxy(proxy);
3193@@ -360,7 +358,7 @@
3194 }
3195 catch (std::exception const& e)
3196 {
3197- BOOST_LOG_SEV(middleware_->runtime()->logger(), Logger::Error)
3198+ BOOST_LOG(middleware_->runtime()->logger())
3199 << "SSRegistryObject: skipping scope \"" << scope.id << "\": " << e.what();
3200 }
3201 }
3202
3203=== modified file 'src/scopes/internal/smartscopes/SSScopeObject.cpp'
3204--- src/scopes/internal/smartscopes/SSScopeObject.cpp 2014-11-18 07:04:04 +0000
3205+++ src/scopes/internal/smartscopes/SSScopeObject.cpp 2015-01-13 07:11:02 +0000
3206@@ -45,10 +45,9 @@
3207 SSRegistryObject::SPtr ss_registry)
3208 : ss_scope_id_(ss_scope_id)
3209 , co_(std::make_shared<SSQueryCtrlObject>())
3210- , qo_(std::make_shared<SSQueryObject>(middleware->runtime()->logger()))
3211+ , qo_(std::make_shared<SSQueryObject>())
3212 , smartscope_(new SmartScope(ss_registry))
3213 , ss_registry_(ss_registry)
3214- , logger_(middleware->runtime()->logger())
3215 {
3216 // Connect the query ctrl to the middleware.
3217 middleware->add_dflt_query_ctrl_object(co_);
3218@@ -173,7 +172,7 @@
3219 catch (...)
3220 {
3221 }
3222- BOOST_LOG_SEV(logger_, Logger::Error) << "SSScopeObject::query(): " << e.what();
3223+ BOOST_LOG(info.mw->runtime()->logger()) << "SSScopeObject::query(): " << e.what();
3224 throw;
3225 }
3226 catch (...)
3227@@ -185,7 +184,7 @@
3228 catch (...)
3229 {
3230 }
3231- BOOST_LOG_SEV(logger_, Logger::Error) << "SSScopeObject::query(): unknown exception";
3232+ BOOST_LOG(info.mw->runtime()->logger()) << "SSScopeObject::query(): unknown exception";
3233 throw;
3234 }
3235
3236
3237=== modified file 'src/scopes/internal/smartscopes/SmartScope.cpp'
3238--- src/scopes/internal/smartscopes/SmartScope.cpp 2014-12-01 08:26:52 +0000
3239+++ src/scopes/internal/smartscopes/SmartScope.cpp 2015-01-13 07:11:02 +0000
3240@@ -19,6 +19,7 @@
3241
3242 #include <unity/scopes/internal/smartscopes/SmartScope.h>
3243
3244+#include <unity/scopes/internal/RuntimeImpl.h>
3245 #include <unity/scopes/PreviewReply.h>
3246 #include <unity/scopes/SearchReply.h>
3247
3248@@ -105,7 +106,7 @@
3249 }
3250 catch (std::exception const& e)
3251 {
3252- BOOST_LOG_SEV(ss_client_->logger(), Logger::Error)
3253+ BOOST_LOG(ss_client_->logger())
3254 << "SmartScope::run(): Failed to register filters for scope '" << filters_data.scope_id
3255 << "': " << e.what();
3256 }
3257@@ -117,7 +118,7 @@
3258 }
3259 catch (std::exception const& e)
3260 {
3261- BOOST_LOG_SEV(ss_client_->logger(), Logger::Error)
3262+ BOOST_LOG(ss_client_->logger())
3263 << "SmartScope::run(): Failed to set filter state for scope '" << filters_data.scope_id
3264 << "': " << e.what();
3265 }
3266@@ -130,7 +131,7 @@
3267 }
3268 catch (std::exception const& e)
3269 {
3270- BOOST_LOG_SEV(this->ss_client_->logger(), Logger::Error)
3271+ BOOST_LOG(this->ss_client_->logger())
3272 << "SmartScope: failed to register category: \"" << category->id
3273 << "\" for scope \"" << scope_id_ << "\" and query: \"" << query_.query_string() << "\"";
3274 }
3275@@ -153,7 +154,7 @@
3276 }
3277 else
3278 {
3279- BOOST_LOG_SEV(this->ss_client_->logger(), Logger::Error)
3280+ BOOST_LOG(this->ss_client_->logger())
3281 << "SmartScope: result for query: \"" << scope_id_ << "\": \"" << query_.query_string()
3282 << "\" returned an invalid cat_id. Skipping result.";
3283 }
3284@@ -166,7 +167,7 @@
3285 }
3286 catch (std::exception const& e)
3287 {
3288- BOOST_LOG_SEV(this->ss_client_->logger(), Logger::Error)
3289+ BOOST_LOG(this->ss_client_->logger())
3290 << "SmartScope::run(): Failed to register departments for scope '" << scope_id_ << "': " << e.what();
3291 }
3292 };
3293
3294=== modified file 'src/scopes/internal/smartscopes/SmartScopesClient.cpp'
3295--- src/scopes/internal/smartscopes/SmartScopesClient.cpp 2014-12-11 16:11:16 +0000
3296+++ src/scopes/internal/smartscopes/SmartScopesClient.cpp 2015-01-13 07:11:02 +0000
3297@@ -19,6 +19,7 @@
3298
3299 #include <unity/scopes/internal/FilterBaseImpl.h>
3300 #include <unity/scopes/internal/FilterStateImpl.h>
3301+#include <unity/scopes/internal/RuntimeImpl.h>
3302 #include <unity/scopes/internal/smartscopes/SmartScopesClient.h>
3303
3304 #include <unity/scopes/ScopeExceptions.h>
3305@@ -54,6 +55,9 @@
3306 static const std::string c_scopes_cache_filename = "remote-scopes.json";
3307 static const std::string c_partner_id_file = "/custom/partner-id";
3308
3309+// Some of the tests don't have a runtime, so we use a separate logger in that case.
3310+BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(test_logger, boost::log::sources::severity_channel_logger_mt<>)
3311+
3312 using namespace unity::scopes;
3313 using namespace unity::scopes::internal::smartscopes;
3314
3315@@ -107,12 +111,13 @@
3316
3317 SmartScopesClient::SmartScopesClient(HttpClientInterface::SPtr http_client,
3318 JsonNodeInterface::SPtr json_node,
3319- boost::log::sources::severity_channel_logger_mt<>& logger,
3320+ RuntimeImpl* runtime,
3321 std::string const& url,
3322 std::string const& partner_id_path)
3323 : http_client_(http_client)
3324 , json_node_(json_node)
3325- , logger_(logger)
3326+ , runtime_(runtime)
3327+ , logger_(runtime ? runtime->logger() : test_logger::get())
3328 , have_latest_cache_(false)
3329 , query_counter_(0)
3330 , partner_file_(partner_id_path)
3331@@ -205,14 +210,13 @@
3332 }
3333 catch (std::exception const& e)
3334 {
3335- BOOST_LOG_SEV(logger_, Logger::Error)
3336+ BOOST_LOG(logger_)
3337 << "SmartScopesClient.get_remote_scopes(): Failed to retrieve remote scopes from uri: "
3338 << url_ << c_remote_scopes_resource << ": " << e.what();
3339
3340 if (caching_enabled)
3341 {
3342- BOOST_LOG_SEV(logger_, Logger::Error)
3343- << "SmartScopesClient.get_remote_scopes(): Using remote scopes from cache";
3344+ BOOST_LOG(logger_) << "SmartScopesClient.get_remote_scopes(): Using remote scopes from cache";
3345
3346 response_str = read_cache();
3347 if (response_str.empty())
3348@@ -239,9 +243,8 @@
3349 }
3350 catch (std::exception const& e)
3351 {
3352- BOOST_LOG_SEV(logger_, Logger::Error)
3353- << "SmartScopesClient.get_remote_scopes() Failed to parse json response from uri: "
3354- << url_ << c_remote_scopes_resource << ": " << e.what();
3355+ BOOST_LOG(logger_) << "SmartScopesClient.get_remote_scopes() Failed to parse json response from uri: "
3356+ << url_ << c_remote_scopes_resource << ": " << e.what();
3357 throw;
3358 }
3359
3360@@ -256,8 +259,7 @@
3361
3362 if (!child_node->has_node("id"))
3363 {
3364- BOOST_LOG_SEV(logger_, Logger::Error)
3365- << "SmartScopesClient.get_remote_scopes(): Skipping scope with no id";
3366+ BOOST_LOG(logger_) << "SmartScopesClient.get_remote_scopes(): Skipping scope with no id";
3367 continue;
3368 }
3369
3370@@ -269,7 +271,7 @@
3371 {
3372 if (!child_node->has_node(field))
3373 {
3374- BOOST_LOG_SEV(logger_, Logger::Error)
3375+ BOOST_LOG(logger_)
3376 << "SmartScopesClient.get_remote_scopes(): Scope: \"" << scope.id
3377 << "\" has no \"" << field << "\" field";
3378 err = true;
3379@@ -277,8 +279,7 @@
3380 }
3381 if (err)
3382 {
3383- BOOST_LOG_SEV(logger_, Logger::Error)
3384- << "SmartScopesClient.get_remote_scopes(): Skipping scope: \"" << scope.id << "\"";
3385+ BOOST_LOG(logger_) << "SmartScopesClient.get_remote_scopes(): Skipping scope: \"" << scope.id << "\"";
3386 continue;
3387 }
3388
3389@@ -317,11 +318,9 @@
3390 scope.version = child_node->has_node("version") ? child_node->get_node("version")->as_int() : 0;
3391 if (scope.version < 0)
3392 {
3393- BOOST_LOG_SEV(logger_, Logger::Error)
3394+ BOOST_LOG(logger_)
3395 << "SmartScopesClient.get_remote_scopes(): Scope: \"" << scope.id
3396- << "\" returned a negative \"version\" value";
3397- BOOST_LOG_SEV(logger_, Logger::Error)
3398- << "SmartScopesClient.get_remote_scopes(): Skipping scope: \"" << scope.id << "\"";
3399+ << "\" returned a negative \"version\" value, skipping scope";
3400 continue;
3401 }
3402
3403@@ -339,7 +338,7 @@
3404 }
3405 catch (unity::LogicException const& e)
3406 {
3407- BOOST_LOG_SEV(logger_, Logger::Error)
3408+ BOOST_LOG(logger_)
3409 << "SmartScopesClient.get_remote_scopes(): Scope: \"" << scope.id
3410 << "\" returned a non-string keyword";
3411 }
3412@@ -347,7 +346,7 @@
3413 }
3414 else
3415 {
3416- BOOST_LOG_SEV(logger_, Logger::Error)
3417+ BOOST_LOG(logger_)
3418 << "SmartScopesClient.get_remote_scopes(): Scope: \"" << scope.id
3419 << "\" returned an invalid value type for \"keywords\"";
3420 }
3421@@ -357,7 +356,7 @@
3422 }
3423 catch (std::exception const& e)
3424 {
3425- BOOST_LOG_SEV(logger_, Logger::Error)
3426+ BOOST_LOG(logger_)
3427 << "SmartScopesClient.get_remote_scopes(): Skipping scope: \""
3428 << scope.id << "\" due to a json parsing failure: " << e.what();
3429 }
3430@@ -365,7 +364,7 @@
3431
3432 if (remote_scopes.empty())
3433 {
3434- BOOST_LOG_SEV(logger_, Logger::Error)
3435+ BOOST_LOG(logger_)
3436 << "SmartScopesClient.get_remote_scopes(): No valid remote scopes retrieved from uri: "
3437 << url_ << c_remote_scopes_resource;
3438 }
3439@@ -379,7 +378,7 @@
3440 }
3441 catch (std::exception const& e)
3442 {
3443- BOOST_LOG_SEV(logger_, Logger::Error)
3444+ BOOST_LOG(logger_)
3445 << "SmartScopesClient.get_remote_scopes(): Failed to write to cache file: "
3446 << c_scopes_cache_dir << c_scopes_cache_filename << ": " << e.what();
3447 }
3448@@ -477,7 +476,7 @@
3449 }
3450 catch (std::exception const &e)
3451 {
3452- BOOST_LOG_SEV(logger_, Logger::Error) << "SmartScopesClient.search(): Failed to parse: " << e.what();
3453+ BOOST_LOG(logger_) << "SmartScopesClient.search(): Failed to parse: " << e.what();
3454 }
3455 }, headers);
3456
3457@@ -541,18 +540,13 @@
3458 }
3459 catch (std::exception const &e)
3460 {
3461- BOOST_LOG_SEV(logger_, Logger::Error) << "SmartScopesClient.preview(): Failed to parse: " << e.what();
3462+ BOOST_LOG(logger_) << "SmartScopesClient.preview(): Failed to parse: " << e.what();
3463 }
3464 }, headers);
3465
3466 return PreviewHandle::UPtr(new PreviewHandle(preview_id, shared_from_this()));
3467 }
3468
3469-boost::log::sources::severity_channel_logger_mt<>& SmartScopesClient::logger() const
3470-{
3471- return logger_;
3472-}
3473-
3474 void SmartScopesClient::parse_line(std::string const& json, PreviewReplyHandler const& handler)
3475 {
3476 JsonNodeInterface::SPtr root_node;
3477@@ -703,7 +697,7 @@
3478 }
3479 catch (std::exception const& e)
3480 {
3481- BOOST_LOG_SEV(logger_, Logger::Error)
3482+ BOOST_LOG(logger_)
3483 << "SmartScopesClient.get_search_results(): Failed to retrieve search results for query "
3484 << search_id << ": " << e.what();
3485 throw;
3486@@ -752,7 +746,7 @@
3487 catch (std::exception const& e)
3488 {
3489 // error in one subdepartment is not critical - just ignore it
3490- BOOST_LOG_SEV(logger_, Logger::Error)
3491+ BOOST_LOG(logger_)
3492 << "SmartScopesClient::parse_departments(): Error parsing subdepartment of department '"
3493 << dep->label << "': " << e.what();
3494 }
3495@@ -809,7 +803,7 @@
3496 }
3497 catch (std::exception const& e)
3498 {
3499- BOOST_LOG_SEV(logger_, Logger::Error)
3500+ BOOST_LOG(logger_)
3501 << "SmartScopesClient.get_preview_results(): Failed to retrieve preview results for query "
3502 << preview_id;
3503 throw;
3504@@ -925,7 +919,7 @@
3505 setting_valid = true;
3506 break;
3507 default:
3508- BOOST_LOG_SEV(logger_, Logger::Error)
3509+ BOOST_LOG(logger_)
3510 << "SmartScopesClient.stringify_settings(): Ignoring unsupported Variant type for settings value: \""
3511 << setting.first << "\"";
3512 }
3513@@ -946,3 +940,8 @@
3514 }
3515 return result_str.str();
3516 }
3517+
3518+boost::log::sources::severity_channel_logger_mt<>& SmartScopesClient::logger() const
3519+{
3520+ return logger_;
3521+}
3522
3523=== modified file 'src/scopes/internal/zmq_middleware/ObjectAdapter.cpp'
3524--- src/scopes/internal/zmq_middleware/ObjectAdapter.cpp 2014-11-18 07:04:04 +0000
3525+++ src/scopes/internal/zmq_middleware/ObjectAdapter.cpp 2015-01-13 07:11:02 +0000
3526@@ -56,11 +56,17 @@
3527
3528 char const* pump_suffix = "-pump";
3529
3530+// Some tests use a nullptr for the run time, so we use different loggers in that case.
3531+
3532+BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(oa_test_logger, boost::log::sources::severity_channel_logger_mt<>)
3533+
3534+BOOST_LOG_INLINE_GLOBAL_LOGGER_CTOR_ARGS(
3535+ oa_test_ipc_logger,
3536+ boost::log::sources::severity_channel_logger_mt<>,
3537+ ((boost::log::keywords::severity = Logger::Trace, boost::log::keywords::channel = "IPC")))
3538+
3539 } // namespace
3540
3541-// Some tests use a nullptr for the run time, so we use a different logger in that case.
3542-BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(object_adapter_test_logger, boost::log::sources::severity_channel_logger_mt<>)
3543-
3544 ObjectAdapter::ObjectAdapter(ZmqMiddleware& mw, string const& name, string const& endpoint, RequestMode m,
3545 int pool_size, int64_t idle_timeout) :
3546 mw_(mw),
3547@@ -69,8 +75,7 @@
3548 mode_(m),
3549 pool_size_(pool_size),
3550 idle_timeout_(idle_timeout != -1 ? idle_timeout : zmqpp::poller::wait_forever),
3551- state_(Inactive),
3552- logger_(mw.runtime() ? mw.runtime()->logger() : object_adapter_test_logger::get())
3553+ state_(Inactive)
3554 {
3555 assert(!name.empty());
3556 assert(!endpoint.empty());
3557@@ -86,12 +91,12 @@
3558 }
3559 catch (std::exception const& e)
3560 {
3561- BOOST_LOG_SEV(logger_, Logger::Error) << "~ObjectAdapter(): exception from shutdown(): " << e.what();
3562+ BOOST_LOG(logger()) << "~ObjectAdapter(): exception from shutdown(): " << e.what();
3563 }
3564 // LCOV_EXCL_START
3565 catch (...)
3566 {
3567- BOOST_LOG_SEV(logger_, Logger::Error) << "~ObjectAdapter(): unknown exception from shutdown()";
3568+ BOOST_LOG(logger()) << "~ObjectAdapter(): unknown exception from shutdown()";
3569 }
3570 // LCOV_EXCL_STOP
3571
3572@@ -103,12 +108,12 @@
3573 }
3574 catch (std::exception const& e)
3575 {
3576- BOOST_LOG_SEV(logger_, Logger::Error) << "~ObjectAdapter(): exception from wait_for_shutdown(): " << e.what();
3577+ BOOST_LOG(logger()) << "~ObjectAdapter(): exception from wait_for_shutdown(): " << e.what();
3578 }
3579 // LCOV_EXCL_START
3580 catch (...)
3581 {
3582- BOOST_LOG_SEV(logger_, Logger::Error) << "~ObjectAdapter(): unknown exception from wait_for_shutdown()";
3583+ BOOST_LOG(logger()) << "~ObjectAdapter(): unknown exception from wait_for_shutdown()";
3584 }
3585 // LCOV_EXCL_STOP
3586 }
3587@@ -729,7 +734,7 @@
3588 }
3589 else
3590 {
3591- BOOST_LOG_SEV(logger_, Logger::Error)
3592+ BOOST_LOG(logger())
3593 << "ObjectAdapter: invalid oneway message header "
3594 << "(id: " << current.id << ", adapter: " << name_ << ", op: " << current.op_name << ")";
3595 }
3596@@ -751,7 +756,7 @@
3597 }
3598 else
3599 {
3600- BOOST_LOG_SEV(logger_, Logger::Error)
3601+ BOOST_LOG(logger())
3602 << "ObjectAdapter: twoway invocation sent to oneway adapter "
3603 << "(id: " << current.id << ", adapter: " << name_ << ", op: " << current.op_name << ")";
3604 }
3605@@ -774,7 +779,7 @@
3606 }
3607 else
3608 {
3609- BOOST_LOG_SEV(logger_, Logger::Error) << s.str();
3610+ BOOST_LOG(logger()) << s.str();
3611 }
3612 return;
3613 }
3614@@ -800,6 +805,12 @@
3615 auto exr = create_object_not_exist_response(b, current);
3616 sender.send(exr);
3617 }
3618+ else
3619+ {
3620+ BOOST_LOG_SEV(logger(), Logger::Warning)
3621+ << "ObjectAdapter: no servant for oneway request "
3622+ << "(id: " << current.id << ", adapter: " << name_ << ", op: " << current.op_name << ")";
3623+ }
3624 return;
3625 }
3626
3627@@ -808,9 +819,11 @@
3628 auto in_params = req.getInParams();
3629 capnp::MallocMessageBuilder b;
3630 auto r = b.initRoot<capnproto::Response>();
3631+ trace_dispatch(current);
3632 servant->safe_dispatch_(current, in_params, r); // noexcept
3633 if (mode_ == RequestMode::Twoway)
3634 {
3635+ BOOST_LOG(ipc_logger()) << decode_status(b.getRoot<capnproto::Response>());
3636 pump.send(client_address, zmqpp::socket::send_more);
3637 pump.send("", zmqpp::socket::send_more);
3638 sender.send(b.getSegmentsForOutput());
3639@@ -853,6 +866,26 @@
3640 state_changed_.notify_all();
3641 }
3642
3643+boost::log::sources::severity_channel_logger_mt<>& ObjectAdapter::logger() const
3644+{
3645+ return mw_.runtime() ? mw_.runtime()->logger() : oa_test_logger::get();
3646+}
3647+
3648+boost::log::sources::severity_channel_logger_mt<>& ObjectAdapter::ipc_logger() const
3649+{
3650+ return mw_.runtime() ? mw_.runtime()->logger(Logger::Channel::IPC) : oa_test_ipc_logger::get();
3651+}
3652+
3653+void ObjectAdapter::trace_dispatch(Current const& c)
3654+{
3655+ BOOST_LOG(ipc_logger())
3656+ << "received request: "
3657+ << "op = " << c.op_name
3658+ << ", id = " << c.id
3659+ << ", cat = " << c.category
3660+ << ", mode = " << (mode_ == RequestMode::Oneway ? "oneway" : "twoway");
3661+}
3662+
3663 } // namespace zmq_middleware
3664
3665 } // namespace internal
3666
3667=== modified file 'src/scopes/internal/zmq_middleware/ZmqException.cpp'
3668--- src/scopes/internal/zmq_middleware/ZmqException.cpp 2014-09-08 05:55:39 +0000
3669+++ src/scopes/internal/zmq_middleware/ZmqException.cpp 2015-01-13 07:11:02 +0000
3670@@ -123,9 +123,58 @@
3671 {
3672 throw MiddlewareException(payload.getUnknown().cStr());
3673 }
3674- default:
3675- break;
3676- }
3677+ // LCOV_EXCL_START
3678+ default:
3679+ {
3680+ assert(false);
3681+ }
3682+ // LCOV_EXCL_STOP
3683+ }
3684+}
3685+
3686+string decode_runtime_exception(capnproto::Response::Reader const& response)
3687+{
3688+ assert(response.getStatus() == capnproto::ResponseStatus::RUNTIME_EXCEPTION);
3689+
3690+ try
3691+ {
3692+ throw_if_runtime_exception(response);
3693+ return ""; // LCOV_EXCL_LINE (not reached, dummy return to prevent compiler warning
3694+ }
3695+ catch (MiddlewareException const& e)
3696+ {
3697+ return e.what();
3698+ }
3699+}
3700+
3701+string decode_status(capnproto::Response::Reader const& response)
3702+{
3703+ string s;
3704+ switch (response.getStatus())
3705+ {
3706+ case capnproto::ResponseStatus::SUCCESS:
3707+ {
3708+ s = "status = Success";
3709+ break;
3710+ }
3711+ case capnproto::ResponseStatus::USER_EXCEPTION:
3712+ {
3713+ s = "status = User exception";
3714+ break;
3715+ }
3716+ case capnproto::ResponseStatus::RUNTIME_EXCEPTION:
3717+ {
3718+ s = decode_runtime_exception(response);
3719+ break;
3720+ }
3721+ // LCOV_EXCL_START
3722+ default:
3723+ {
3724+ assert(false);
3725+ }
3726+ // LCOV_EXCL_STOP
3727+ }
3728+ return s;
3729 }
3730
3731 } // namespace zmq_middleware
3732
3733=== modified file 'src/scopes/internal/zmq_middleware/ZmqMiddleware.cpp'
3734--- src/scopes/internal/zmq_middleware/ZmqMiddleware.cpp 2014-12-04 03:33:59 +0000
3735+++ src/scopes/internal/zmq_middleware/ZmqMiddleware.cpp 2015-01-13 07:11:02 +0000
3736@@ -166,18 +166,18 @@
3737 auto millisecs = chrono::duration_cast<chrono::milliseconds>(end_time - start_time).count();
3738 if (millisecs > 100)
3739 {
3740- BOOST_LOG_SEV(logger_, Logger::Error)
3741+ BOOST_LOG(logger_)
3742 << "warning: ~ZmqMiddleware(): context_.terminate() took " << millisecs
3743 << " ms to complete for " << server_name_;
3744 }
3745 }
3746 catch (std::exception const& e)
3747 {
3748- BOOST_LOG_SEV(logger_, Logger::Error) << "~ZmqMiddleware(): " << e.what();
3749+ BOOST_LOG(logger_) << "~ZmqMiddleware(): " << e.what();
3750 }
3751 catch (...)
3752 {
3753- BOOST_LOG_SEV(logger_, Logger::Error) << "~ZmqMiddleware(): unknown exception";
3754+ BOOST_LOG(logger_) << "~ZmqMiddleware(): unknown exception";
3755 }
3756 }
3757
3758@@ -559,7 +559,7 @@
3759 }
3760 catch (std::exception const& e) // Can happen during shutdown
3761 {
3762- BOOST_LOG_SEV(logger_, Logger::Error) << "exception in add_query_ctrl_object(): " << e.what();
3763+ BOOST_LOG(logger_) << "exception in add_query_ctrl_object(): " << e.what();
3764 throw;
3765 }
3766 return proxy;
3767@@ -579,7 +579,7 @@
3768 }
3769 catch (std::exception const& e) // Can happen during shutdown
3770 {
3771- BOOST_LOG_SEV(logger_, Logger::Error) << "exception in add_dflt_query_ctrl_object(): " << e.what();
3772+ BOOST_LOG(logger_) << "exception in add_dflt_query_ctrl_object(): " << e.what();
3773 throw;
3774 }
3775 }
3776@@ -601,7 +601,7 @@
3777 }
3778 catch (std::exception const& e) // Can happen during shutdown
3779 {
3780- BOOST_LOG_SEV(logger_, Logger::Error) << "exception in add_query_object(): " << e.what();
3781+ BOOST_LOG(logger_) << "exception in add_query_object(): " << e.what();
3782 throw;
3783 }
3784 return proxy;
3785@@ -621,7 +621,7 @@
3786 }
3787 catch (std::exception const& e) // Can happen during shutdown
3788 {
3789- BOOST_LOG_SEV(logger_, Logger::Error) << "exception in add_dflt_query_object(): " << e.what();
3790+ BOOST_LOG(logger_) << "exception in add_dflt_query_object(): " << e.what();
3791 throw;
3792 }
3793 }
3794@@ -645,7 +645,7 @@
3795 }
3796 catch (std::exception const& e) // Can happen during shutdown
3797 {
3798- BOOST_LOG_SEV(logger_, Logger::Error) << "exception in add_registry_object(): " << e.what();
3799+ BOOST_LOG(logger_) << "exception in add_registry_object(): " << e.what();
3800 throw;
3801 }
3802 return proxy;
3803@@ -668,7 +668,7 @@
3804 }
3805 catch (std::exception const& e) // Can happen during shutdown
3806 {
3807- BOOST_LOG_SEV(logger_, Logger::Error) << "exception in add_reply_object(): " << e.what();
3808+ BOOST_LOG(logger_) << "exception in add_reply_object(): " << e.what();
3809 throw;
3810 }
3811 return proxy;
3812@@ -692,7 +692,7 @@
3813 }
3814 catch (std::exception const& e) // Can happen during shutdown
3815 {
3816- BOOST_LOG_SEV(logger_, Logger::Error) << "exception in add_scope_object(): " << e.what();
3817+ BOOST_LOG(logger_) << "exception in add_scope_object(): " << e.what();
3818 throw;
3819 }
3820 return proxy;
3821@@ -712,7 +712,7 @@
3822 }
3823 catch (std::exception const& e) // Can happen during shutdown
3824 {
3825- BOOST_LOG_SEV(logger_, Logger::Error) << "exception in add_dflt_scope_object(): " << e.what();
3826+ BOOST_LOG(logger_) << "exception in add_dflt_scope_object(): " << e.what();
3827 throw;
3828 }
3829 }
3830@@ -737,7 +737,7 @@
3831 }
3832 catch (std::exception const& e) // Can happen during shutdown
3833 {
3834- BOOST_LOG_SEV(logger_, Logger::Error) << "exception in add_state_receiver_object(): " << e.what();
3835+ BOOST_LOG(logger_) << "exception in add_state_receiver_object(): " << e.what();
3836 throw;
3837 }
3838 return proxy;
3839@@ -826,12 +826,12 @@
3840 if (category == scope_category)
3841 {
3842 auto p = make_shared<ZmqScope>(this, endpoint, identity, category, timeout);
3843- return ScopeImpl::create(p, runtime(), identity);
3844+ return ScopeImpl::create(p, identity);
3845 }
3846 else if (category == registry_category)
3847 {
3848 auto p = make_shared<ZmqRegistry>(this, endpoint, identity, category, timeout);
3849- return make_shared<RegistryImpl>(p, runtime());
3850+ return make_shared<RegistryImpl>(p);
3851 }
3852 else
3853 {
3854
3855=== modified file 'src/scopes/internal/zmq_middleware/ZmqObject.cpp'
3856--- src/scopes/internal/zmq_middleware/ZmqObject.cpp 2014-11-14 07:06:23 +0000
3857+++ src/scopes/internal/zmq_middleware/ZmqObject.cpp 2015-01-13 07:11:02 +0000
3858@@ -166,23 +166,9 @@
3859 return request;
3860 }
3861
3862-#ifdef ENABLE_IPC_MONITOR
3863-void register_monitor_socket(ConnectionPool& pool, zmqpp::context_t const& context)
3864-{
3865- thread_local static bool monitor_initialized = false;
3866- if (!monitor_initialized) {
3867- monitor_initialized = true;
3868- auto monitor_socket = make_shared<zmqpp::socket>(context, zmqpp::socket_type::publish);
3869- monitor_socket->set(zmqpp::socket_option::linger, 0);
3870- monitor_socket->connect(MONITOR_ENDPOINT);
3871- pool.register_socket(MONITOR_ENDPOINT, monitor_socket, false);
3872- }
3873-}
3874-#endif
3875-
3876 // Get a socket to the endpoint for this proxy and write the request on the wire.
3877
3878-void ZmqObjectProxy::invoke_oneway_(capnp::MessageBuilder& in_params)
3879+void ZmqObjectProxy::invoke_oneway_(capnp::MessageBuilder& request)
3880 {
3881 // Each calling thread gets its own pool because zmq sockets are not thread-safe.
3882 thread_local static ConnectionPool pool(*mw_base()->context());
3883@@ -192,30 +178,22 @@
3884 assert(mode_ == RequestMode::Oneway);
3885 shared_ptr<zmqpp::socket> s = pool.find(endpoint_);
3886 ZmqSender sender(*s);
3887- auto segments = in_params.getSegmentsForOutput();
3888+ auto segments = request.getSegmentsForOutput();
3889+ trace_request_(request);
3890 if (!sender.send(segments, ZmqSender::DontWait))
3891 {
3892 // If there is nothing at the other end, discard the message and trash the socket.
3893 pool.remove(endpoint_);
3894 return;
3895 }
3896-
3897-#ifdef ENABLE_IPC_MONITOR
3898- if (true) {
3899- register_monitor_socket(pool, *mw_base()->context());
3900- auto monitor = pool.find(MONITOR_ENDPOINT);
3901- auto word_arr = capnp::messageToFlatArray(segments);
3902- monitor->send_raw(reinterpret_cast<char*>(&word_arr[0]), word_arr.size() * sizeof(capnp::word));
3903- }
3904-#endif
3905 }
3906
3907-ZmqObjectProxy::TwowayOutParams ZmqObjectProxy::invoke_twoway_(capnp::MessageBuilder& in_params)
3908+ZmqObjectProxy::TwowayOutParams ZmqObjectProxy::invoke_twoway_(capnp::MessageBuilder& request)
3909 {
3910- return invoke_twoway_(in_params, timeout_);
3911+ return invoke_twoway_(request, timeout_);
3912 }
3913
3914-ZmqObjectProxy::TwowayOutParams ZmqObjectProxy::invoke_twoway_(capnp::MessageBuilder& in_params,
3915+ZmqObjectProxy::TwowayOutParams ZmqObjectProxy::invoke_twoway_(capnp::MessageBuilder& request,
3916 int64_t twoway_timeout,
3917 int64_t locate_timeout)
3918 {
3919@@ -263,14 +241,14 @@
3920 }
3921
3922 // Try the invocation
3923- return invoke_twoway__(in_params, twoway_timeout);
3924+ return invoke_twoway__(request, twoway_timeout);
3925 }
3926
3927 // Get a socket to the endpoint for this proxy and write the request on the wire.
3928 // Poll for the reply with the given timeout.
3929 // Return a reader for the response or throw if the timeout expires.
3930
3931-ZmqObjectProxy::TwowayOutParams ZmqObjectProxy::invoke_twoway__(capnp::MessageBuilder& in_params, int64_t timeout)
3932+ZmqObjectProxy::TwowayOutParams ZmqObjectProxy::invoke_twoway__(capnp::MessageBuilder& request, int64_t timeout)
3933 {
3934 RequestMode mode;
3935 std::string endpoint;
3936@@ -295,21 +273,10 @@
3937 s.set(zmqpp::socket_option::reconnect_interval_max, reconnect_max);
3938 s.connect(endpoint);
3939 ZmqSender sender(s);
3940- auto segments = in_params.getSegmentsForOutput();
3941+ auto segments = request.getSegmentsForOutput();
3942+ trace_request_(request);
3943 sender.send(segments);
3944
3945-#ifdef ENABLE_IPC_MONITOR
3946- // Each calling thread gets its own pool because zmq sockets are not thread-safe.
3947- thread_local static ConnectionPool pool(*mw_base()->context());
3948-
3949- if (true) {
3950- register_monitor_socket(pool, *mw_base()->context());
3951- auto monitor = pool.find(MONITOR_ENDPOINT);
3952- auto word_arr = capnp::messageToFlatArray(segments);
3953- monitor->send_raw(reinterpret_cast<char*>(&word_arr[0]), word_arr.size() * sizeof(capnp::word));
3954- }
3955-#endif
3956-
3957 zmqpp::poller p;
3958 p.add(s);
3959
3960@@ -324,7 +291,7 @@
3961
3962 if (!p.has_input(s))
3963 {
3964- string op_name = in_params.getRoot<capnproto::Request>().getOpName().cStr();
3965+ string op_name = request.getRoot<capnproto::Request>().getOpName().cStr();
3966 throw TimeoutException("Request timed out after " + std::to_string(timeout) + " milliseconds (endpoint = " +
3967 endpoint + ", op = " + op_name + ")");
3968 }
3969@@ -335,10 +302,46 @@
3970 out_params.receiver.reset(new ZmqReceiver(s));
3971 auto params = out_params.receiver->receive();
3972 out_params.reader.reset(new capnp::SegmentArrayMessageReader(params));
3973+ trace_reply_(request, *out_params.reader);
3974 return out_params;
3975 // Outgoing twoway socket closed here.
3976 }
3977
3978+string ZmqObjectProxy::decode_request_(capnp::MessageBuilder& request)
3979+{
3980+ auto r = request.getRoot<capnproto::Request>();
3981+ auto mode = r.getMode();
3982+ auto op_name = r.getOpName().cStr();
3983+ auto identity = r.getId().cStr();
3984+ auto cat = r.getCat().cStr();
3985+ stringstream s;
3986+ s << "op = " << op_name
3987+ << ", id = " << identity
3988+ << ", cat = " << cat
3989+ << ", mode = " << (mode == capnproto::RequestMode::ONEWAY ? "oneway" : "twoway");
3990+ return s.str();
3991+}
3992+
3993+void ZmqObjectProxy::trace_request_(capnp::MessageBuilder& request)
3994+{
3995+ BOOST_LOG(mw_base()->runtime()->logger(Logger::IPC))
3996+ << "sending request: "
3997+ << decode_request_(request);
3998+}
3999+
4000+string ZmqObjectProxy::decode_reply_(capnp::MessageBuilder& request, capnp::MessageReader& reply)
4001+{
4002+ auto response = reply.getRoot<capnproto::Response>();
4003+ return decode_request_(request) + ", " + decode_status(response);
4004+}
4005+
4006+void ZmqObjectProxy::trace_reply_(capnp::MessageBuilder& request, capnp::MessageReader& reply)
4007+{
4008+ BOOST_LOG(mw_base()->runtime()->logger(Logger::IPC))
4009+ << "received reply: "
4010+ << decode_reply_(request, reply);
4011+}
4012+
4013 } // namespace zmq_middleware
4014
4015 } // namespace internal
4016
4017=== modified file 'src/scopes/internal/zmq_middleware/ZmqRegistry.cpp'
4018--- src/scopes/internal/zmq_middleware/ZmqRegistry.cpp 2014-11-14 07:04:55 +0000
4019+++ src/scopes/internal/zmq_middleware/ZmqRegistry.cpp 2015-01-13 07:11:02 +0000
4020@@ -167,7 +167,7 @@
4021 proxy.getIdentity(),
4022 proxy.getCategory(),
4023 proxy.getTimeout());
4024- return ScopeImpl::create(zmq_proxy, mw->runtime(), identity);
4025+ return ScopeImpl::create(zmq_proxy, identity);
4026 }
4027 case capnproto::Registry::LocateResponse::Response::NOT_FOUND_EXCEPTION:
4028 {
4029
4030=== modified file 'src/scopes/internal/zmq_middleware/ZmqScope.cpp'
4031--- src/scopes/internal/zmq_middleware/ZmqScope.cpp 2014-11-20 05:29:23 +0000
4032+++ src/scopes/internal/zmq_middleware/ZmqScope.cpp 2015-01-13 07:11:02 +0000
4033@@ -18,7 +18,6 @@
4034
4035 #include <unity/scopes/internal/zmq_middleware/ZmqScope.h>
4036
4037-#include <unity/scopes/internal/Logger.h>
4038 #include <unity/scopes/internal/QueryCtrlImpl.h>
4039 #include <unity/scopes/internal/RuntimeImpl.h>
4040 #include <scopes/internal/zmq_middleware/capnproto/Scope.capnp.h>
4041@@ -105,7 +104,7 @@
4042 proxy.getEndpoint().cStr(),
4043 proxy.getIdentity().cStr(),
4044 proxy.getCategory().cStr()));
4045- return make_shared<QueryCtrlImpl>(p, reply_proxy, mw_base()->runtime()->logger());
4046+ return make_shared<QueryCtrlImpl>(p, reply_proxy);
4047 }
4048
4049 QueryCtrlProxy ZmqScope::activate(VariantMap const& result, VariantMap const& hints, MWReplyProxy const& reply)
4050@@ -135,7 +134,7 @@
4051 proxy.getEndpoint().cStr(),
4052 proxy.getIdentity().cStr(),
4053 proxy.getCategory().cStr()));
4054- return make_shared<QueryCtrlImpl>(p, reply_proxy, mw_base()->runtime()->logger());
4055+ return make_shared<QueryCtrlImpl>(p, reply_proxy);
4056 }
4057
4058 QueryCtrlProxy ZmqScope::perform_action(VariantMap const& result,
4059@@ -168,7 +167,7 @@
4060 proxy.getEndpoint().cStr(),
4061 proxy.getIdentity().cStr(),
4062 proxy.getCategory().cStr()));
4063- return make_shared<QueryCtrlImpl>(p, reply_proxy, mw_base()->runtime()->logger());
4064+ return make_shared<QueryCtrlImpl>(p, reply_proxy);
4065 }
4066
4067 QueryCtrlProxy ZmqScope::preview(VariantMap const& result, VariantMap const& hints, MWReplyProxy const& reply)
4068@@ -198,7 +197,7 @@
4069 proxy.getEndpoint().cStr(),
4070 proxy.getIdentity().cStr(),
4071 proxy.getCategory().cStr()));
4072- return make_shared<QueryCtrlImpl>(p, reply_proxy, mw_base()->runtime()->logger());
4073+ return make_shared<QueryCtrlImpl>(p, reply_proxy);
4074 }
4075
4076 bool ZmqScope::debug_mode()
4077
4078=== modified file 'src/scopes/testing/InProcessBenchmark.cpp'
4079--- src/scopes/testing/InProcessBenchmark.cpp 2014-08-28 00:20:56 +0000
4080+++ src/scopes/testing/InProcessBenchmark.cpp 2015-01-13 07:11:02 +0000
4081@@ -208,6 +208,10 @@
4082 {
4083 return true;
4084 }
4085+
4086+ void push_surfacing_results_from_cache() override
4087+ {
4088+ }
4089 };
4090
4091 typedef std::chrono::high_resolution_clock Clock;
4092
4093=== modified file 'src/scopes/utility/internal/BufferedResultForwarderImpl.cpp'
4094--- src/scopes/utility/internal/BufferedResultForwarderImpl.cpp 2014-12-01 09:47:04 +0000
4095+++ src/scopes/utility/internal/BufferedResultForwarderImpl.cpp 2015-01-13 07:11:02 +0000
4096@@ -72,7 +72,7 @@
4097 // scope author tells us that results for this forwarder are now ready
4098 // to be displayed (or the query has finished); set the 'ready' flag
4099 // and if previous forwarder is also ready, then push and disable
4100- // futher buffering.
4101+ // further buffering.
4102 if (!ready_.exchange(true))
4103 {
4104 if (previous_ready_ || !has_previous_)
4105
4106=== modified file 'src/scopes/utility/internal/BufferedSearchReplyImpl.cpp'
4107--- src/scopes/utility/internal/BufferedSearchReplyImpl.cpp 2014-12-01 01:51:38 +0000
4108+++ src/scopes/utility/internal/BufferedSearchReplyImpl.cpp 2015-01-13 07:11:02 +0000
4109@@ -92,6 +92,11 @@
4110 return upstream_->push(filters, filter_state);
4111 }
4112
4113+void BufferedSearchReplyImpl::push_surfacing_results_from_cache()
4114+{
4115+ upstream_->push_surfacing_results_from_cache();
4116+}
4117+
4118 void BufferedSearchReplyImpl::finished()
4119 {
4120 upstream_->finished();
4121
4122=== modified file 'test/gtest/scopes/Activation/Activation_test.cpp'
4123--- test/gtest/scopes/Activation/Activation_test.cpp 2014-12-04 04:33:50 +0000
4124+++ test/gtest/scopes/Activation/Activation_test.cpp 2015-01-13 07:11:02 +0000
4125@@ -554,7 +554,7 @@
4126 auto mw = rt->factory()->create("TestScope", "Zmq", TEST_DIR "/Zmq.ini");
4127 mw->start();
4128 auto proxy = mw->create_scope_proxy("TestScope");
4129- auto scope = internal::ScopeImpl::create(proxy, rt.get(), "TestScope");
4130+ auto scope = internal::ScopeImpl::create(proxy, "TestScope");
4131
4132 VariantMap hints;
4133 auto receiver = std::make_shared<SearchReceiver>();
4134
4135=== modified file 'test/gtest/scopes/Activation/Runtime.ini.in'
4136--- test/gtest/scopes/Activation/Runtime.ini.in 2014-09-05 04:00:28 +0000
4137+++ test/gtest/scopes/Activation/Runtime.ini.in 2015-01-13 07:11:02 +0000
4138@@ -3,3 +3,4 @@
4139 Registry.ConfigFile = @CMAKE_CURRENT_BINARY_DIR@/Registry.ini
4140 Default.Middleware = Zmq
4141 Zmq.ConfigFile = @CMAKE_CURRENT_BINARY_DIR@/Zmq.ini
4142+LogDir=
4143
4144=== modified file 'test/gtest/scopes/CMakeLists.txt'
4145--- test/gtest/scopes/CMakeLists.txt 2014-12-01 01:51:38 +0000
4146+++ test/gtest/scopes/CMakeLists.txt 2015-01-13 07:11:02 +0000
4147@@ -25,6 +25,7 @@
4148 add_subdirectory(RangeInputFilter)
4149 add_subdirectory(RatingFilter)
4150 add_subdirectory(ReplyReaper)
4151+add_subdirectory(ResultCache)
4152 add_subdirectory(SwitchFilter)
4153 add_subdirectory(ValueSliderFilter)
4154 add_subdirectory(PreviewWidget)
4155
4156=== modified file 'test/gtest/scopes/Filters/Filters_test.cpp'
4157--- test/gtest/scopes/Filters/Filters_test.cpp 2014-12-04 04:33:50 +0000
4158+++ test/gtest/scopes/Filters/Filters_test.cpp 2015-01-13 07:11:02 +0000
4159@@ -124,7 +124,7 @@
4160 auto mw = rt->factory()->create("TestScope", "Zmq", TEST_DIR "/Zmq.ini");
4161 mw->start();
4162 auto proxy = mw->create_scope_proxy("TestScope");
4163- auto scope = internal::ScopeImpl::create(proxy, rt.get(), "TestScope");
4164+ auto scope = internal::ScopeImpl::create(proxy, "TestScope");
4165
4166 SearchMetadata hints("pl", "phone");
4167 auto receiver = std::make_shared<SearchReceiver>();
4168
4169=== modified file 'test/gtest/scopes/Filters/Runtime.ini.in'
4170--- test/gtest/scopes/Filters/Runtime.ini.in 2014-09-05 04:00:28 +0000
4171+++ test/gtest/scopes/Filters/Runtime.ini.in 2015-01-13 07:11:02 +0000
4172@@ -3,3 +3,4 @@
4173 Registry.ConfigFile = @CMAKE_CURRENT_BINARY_DIR@/Registry.ini
4174 Default.Middleware = Zmq
4175 Zmq.ConfigFile = @CMAKE_CURRENT_BINARY_DIR@/Zmq.ini
4176+LogDir=
4177
4178=== modified file 'test/gtest/scopes/IdleShutdown/IdleShutdown_test.cpp'
4179--- test/gtest/scopes/IdleShutdown/IdleShutdown_test.cpp 2014-12-05 08:21:06 +0000
4180+++ test/gtest/scopes/IdleShutdown/IdleShutdown_test.cpp 2015-01-13 07:11:02 +0000
4181@@ -129,7 +129,7 @@
4182 auto mw = rt->factory()->create("client_middleware", "Zmq", "Zmq.ini");
4183 mw->start();
4184 auto proxy = mw->create_scope_proxy("SlowSearchScope");
4185- auto scope = internal::ScopeImpl::create(proxy, rt.get(), "SlowSearchScope");
4186+ auto scope = internal::ScopeImpl::create(proxy, "SlowSearchScope");
4187
4188 // Create a query, which takes 4 seconds to complete in the scope.
4189 auto receiver = make_shared<NullReceiver>();
4190
4191=== modified file 'test/gtest/scopes/IdleShutdown/Runtime.ini.in'
4192--- test/gtest/scopes/IdleShutdown/Runtime.ini.in 2014-07-18 06:41:02 +0000
4193+++ test/gtest/scopes/IdleShutdown/Runtime.ini.in 2015-01-13 07:11:02 +0000
4194@@ -3,3 +3,4 @@
4195 Registry.ConfigFile = Registry.ini
4196 Default.Middleware = Zmq
4197 Zmq.ConfigFile = Zmq.ini
4198+LogDir=
4199
4200=== modified file 'test/gtest/scopes/Invocation/Invocation_test.cpp'
4201--- test/gtest/scopes/Invocation/Invocation_test.cpp 2014-12-04 04:33:50 +0000
4202+++ test/gtest/scopes/Invocation/Invocation_test.cpp 2015-01-13 07:11:02 +0000
4203@@ -118,7 +118,7 @@
4204 auto mw = rt->factory()->create("TestScope", "Zmq", "Zmq.ini");
4205 mw->start();
4206 auto proxy = mw->create_scope_proxy("TestScope");
4207- auto scope = internal::ScopeImpl::create(proxy, rt.get(), "TestScope");
4208+ auto scope = internal::ScopeImpl::create(proxy, "TestScope");
4209
4210 auto receiver = make_shared<TestReceiver>();
4211
4212@@ -150,7 +150,7 @@
4213 auto mw = rt->factory()->create("DebugTestScope", "Zmq", "Zmq.ini");
4214 mw->start();
4215 auto proxy = mw->create_scope_proxy("DebugTestScope");
4216- auto scope = internal::ScopeImpl::create(proxy, rt.get(), "TestScope");
4217+ auto scope = internal::ScopeImpl::create(proxy, "TestScope");
4218
4219 auto receiver = make_shared<TestReceiver>();
4220
4221@@ -186,7 +186,7 @@
4222 auto mw = rt->factory()->create("EmptyScope", "Zmq", "Zmq.ini");
4223 mw->start();
4224 auto proxy = mw->create_scope_proxy("EmptyScope");
4225- auto scope = internal::ScopeImpl::create(proxy, rt.get(), "EmptyScope");
4226+ auto scope = internal::ScopeImpl::create(proxy, "EmptyScope");
4227
4228 auto receiver = make_shared<NullReceiver>();
4229
4230
4231=== modified file 'test/gtest/scopes/Invocation/Runtime.ini.in'
4232--- test/gtest/scopes/Invocation/Runtime.ini.in 2014-07-18 07:09:57 +0000
4233+++ test/gtest/scopes/Invocation/Runtime.ini.in 2015-01-13 07:11:02 +0000
4234@@ -3,3 +3,4 @@
4235 Registry.ConfigFile = Registry.ini
4236 Default.Middleware = Zmq
4237 Zmq.ConfigFile = Zmq.ini
4238+LogDir=
4239
4240=== modified file 'test/gtest/scopes/Registry/Runtime.ini.in'
4241--- test/gtest/scopes/Registry/Runtime.ini.in 2014-05-08 06:04:29 +0000
4242+++ test/gtest/scopes/Registry/Runtime.ini.in 2015-01-13 07:11:02 +0000
4243@@ -4,3 +4,4 @@
4244 Default.Middleware = Zmq
4245 Zmq.ConfigFile = @CMAKE_CURRENT_BINARY_DIR@/Zmq.ini
4246 Smartscopes.Registry.Identity =
4247+LogDir=
4248
4249=== modified file 'test/gtest/scopes/ReplyReaper/ReplyReaper_test.cpp'
4250--- test/gtest/scopes/ReplyReaper/ReplyReaper_test.cpp 2014-12-04 04:33:50 +0000
4251+++ test/gtest/scopes/ReplyReaper/ReplyReaper_test.cpp 2015-01-13 07:11:02 +0000
4252@@ -99,7 +99,7 @@
4253 auto mw = rt->factory()->create("NoReplyScope", "Zmq", TEST_DIR "/Zmq.ini");
4254 mw->start();
4255 auto proxy = mw->create_scope_proxy("NoReplyScope");
4256- auto scope = internal::ScopeImpl::create(proxy, rt.get(), "NoReplyScope");
4257+ auto scope = internal::ScopeImpl::create(proxy, "NoReplyScope");
4258
4259 auto receiver = make_shared<NullReceiver>();
4260 scope->search("test", SearchMetadata("en", "phone"), receiver);
4261@@ -171,7 +171,7 @@
4262 auto mw = rt->factory()->create("NoReplyScope", "Zmq", TEST_DIR "/Zmq.ini");
4263 mw->start();
4264 auto proxy = mw->create_scope_proxy("NoReplyScope");
4265- auto scope = internal::ScopeImpl::create(proxy, rt.get(), "NoReplyScope");
4266+ auto scope = internal::ScopeImpl::create(proxy, "NoReplyScope");
4267
4268 auto receiver = make_shared<NoReapReceiver>();
4269 scope->search("test", SearchMetadata("en", "phone"), receiver);
4270
4271=== modified file 'test/gtest/scopes/ReplyReaper/Runtime.ini.in'
4272--- test/gtest/scopes/ReplyReaper/Runtime.ini.in 2014-07-29 06:16:45 +0000
4273+++ test/gtest/scopes/ReplyReaper/Runtime.ini.in 2015-01-13 07:11:02 +0000
4274@@ -5,3 +5,4 @@
4275 Reap.Interval = 1
4276 Default.Middleware = Zmq
4277 Zmq.ConfigFile = @CMAKE_CURRENT_BINARY_DIR@/Zmq.ini
4278+LogDir=
4279
4280=== added directory 'test/gtest/scopes/ResultCache'
4281=== added file 'test/gtest/scopes/ResultCache/CMakeLists.txt'
4282--- test/gtest/scopes/ResultCache/CMakeLists.txt 1970-01-01 00:00:00 +0000
4283+++ test/gtest/scopes/ResultCache/CMakeLists.txt 2015-01-13 07:11:02 +0000
4284@@ -0,0 +1,27 @@
4285+configure_file(TestRegistry.ini.in ${CMAKE_CURRENT_BINARY_DIR}/TestRegistry.ini)
4286+configure_file(Runtime.ini.in ${CMAKE_CURRENT_BINARY_DIR}/Runtime.ini)
4287+configure_file(Zmq.ini.in ${CMAKE_CURRENT_BINARY_DIR}/Zmq.ini)
4288+
4289+add_definitions(-DTEST_SOURCE_PATH="${CMAKE_CURRENT_SOURCE_DIR}")
4290+add_definitions(-DTEST_RUNTIME_PATH="${CMAKE_CURRENT_BINARY_DIR}")
4291+add_definitions(-DTEST_RUNTIME_FILE="${CMAKE_CURRENT_BINARY_DIR}/Runtime.ini")
4292+add_definitions(-DTEST_REGISTRY_PATH="${PROJECT_BINARY_DIR}/scoperegistry")
4293+
4294+add_executable(ResultCache_test ResultCache_test.cpp CacheScope.cpp)
4295+target_link_libraries(ResultCache_test ${TESTLIBS})
4296+
4297+add_dependencies(ResultCache_test scoperegistry scoperunner)
4298+
4299+add_test(ResultCache ResultCache_test)
4300+
4301+set(SCOPE_DIR "${CMAKE_CURRENT_BINARY_DIR}/scopes")
4302+
4303+foreach (scope CacheScope AlwaysPushFromCacheScope)
4304+ file(MAKE_DIRECTORY "${SCOPE_DIR}/${scope}")
4305+ configure_file(CacheScope.ini.in ${SCOPE_DIR}/${scope}/${scope}.ini)
4306+ add_library(${scope} MODULE CacheScope.cpp)
4307+ set_target_properties(${scope}
4308+ PROPERTIES
4309+ LIBRARY_OUTPUT_DIRECTORY "${SCOPE_DIR}/${scope}/"
4310+ )
4311+endforeach()
4312
4313=== added file 'test/gtest/scopes/ResultCache/CacheScope.cpp'
4314--- test/gtest/scopes/ResultCache/CacheScope.cpp 1970-01-01 00:00:00 +0000
4315+++ test/gtest/scopes/ResultCache/CacheScope.cpp 2015-01-13 07:11:02 +0000
4316@@ -0,0 +1,146 @@
4317+/*
4318+ * Copyright (C) 2015 Canonical Ltd
4319+ *
4320+ * This program is free software: you can redistribute it and/or modify
4321+ * it under the terms of the GNU Lesser General Public License version 3 as
4322+ * published by the Free Software Foundation.
4323+ *
4324+ * This program is distributed in the hope that it will be useful,
4325+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4326+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4327+ * GNU Lesser General Public License for more details.
4328+ *
4329+ * You should have received a copy of the GNU Lesser General Public License
4330+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4331+ *
4332+ * Authored by: Michi Henning <michi.henning@canonical.com>
4333+ */
4334+
4335+#include "CacheScope.h"
4336+
4337+#include <unity/scopes/CategorisedResult.h>
4338+#include <unity/scopes/ScopeBase.h>
4339+#include <unity/scopes/ScopeExceptions.h>
4340+#include <unity/scopes/SearchReply.h>
4341+
4342+#include <boost/filesystem.hpp>
4343+#include <unity/UnityExceptions.h>
4344+#include <unity/util/FileIO.h>
4345+
4346+#include <atomic>
4347+#include <mutex>
4348+
4349+using namespace std;
4350+using namespace unity::scopes;
4351+
4352+namespace
4353+{
4354+
4355+class TestQuery : public SearchQueryBase
4356+{
4357+public:
4358+ TestQuery(CannedQuery const& query,
4359+ SearchMetadata const& metadata,
4360+ string const& id,
4361+ RegistryProxy const& reg)
4362+ : SearchQueryBase(query, metadata)
4363+ , id_(id)
4364+ , registry_(reg)
4365+ {
4366+ }
4367+
4368+ virtual void cancelled() override
4369+ {
4370+ }
4371+
4372+ virtual void run(SearchReplyProxy const& reply) override
4373+ {
4374+ if (id_ == "AlwaysPushFromCacheScope")
4375+ {
4376+ // So we get coverage on pushing from cache before a cache file exists.
4377+ reply->push_surfacing_results_from_cache();
4378+ return;
4379+ }
4380+
4381+ if (query().query_string().empty())
4382+ {
4383+ // If there is a cache file, we use it to push.
4384+ boost::system::error_code ec;
4385+ if (boost::filesystem::exists(TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache", ec))
4386+ {
4387+ reply->push_surfacing_results_from_cache();
4388+ // We do this twice, to get coverage on the double-call guard.
4389+ reply->push_surfacing_results_from_cache();
4390+ return;
4391+ }
4392+ }
4393+ else if (query().query_string() == "non-empty from cache")
4394+ {
4395+ // This gives us coverage for the case that we are pushing from the cache for a non-empty query.
4396+ reply->push_surfacing_results_from_cache();
4397+ return;
4398+ }
4399+
4400+ auto depts = Department::create("", query(), "Top");
4401+ auto sub_dept = Department::create("sub" + query().query_string(), query(), "Sub");
4402+ depts->add_subdepartment(move(sub_dept));
4403+ reply->register_departments(move(depts));
4404+ auto cat = reply->register_category(id_, "", "");
4405+ CategorisedResult res(cat);
4406+ res.set_uri("uri");
4407+ res.set_title(query().query_string());
4408+ if (valid())
4409+ {
4410+ reply->push(res);
4411+ }
4412+ }
4413+
4414+private:
4415+ string id_;
4416+ RegistryProxy registry_;
4417+};
4418+
4419+} // namespace
4420+
4421+void CacheScope::start(string const& scope_id)
4422+{
4423+ lock_guard<mutex> lock(mutex_);
4424+ id_ = scope_id;
4425+}
4426+
4427+void CacheScope::stop()
4428+{
4429+}
4430+
4431+void CacheScope::run()
4432+{
4433+}
4434+
4435+SearchQueryBase::UPtr CacheScope::search(CannedQuery const& query, SearchMetadata const& metadata)
4436+{
4437+ lock_guard<mutex> lock(mutex_);
4438+ return SearchQueryBase::UPtr(new TestQuery(query, metadata, id_, registry()));
4439+}
4440+
4441+PreviewQueryBase::UPtr CacheScope::preview(Result const&, ActionMetadata const &)
4442+{
4443+ return nullptr; // unused
4444+}
4445+
4446+extern "C"
4447+{
4448+
4449+ unity::scopes::ScopeBase*
4450+ // cppcheck-suppress unusedFunction
4451+ UNITY_SCOPE_CREATE_FUNCTION()
4452+ {
4453+ return new CacheScope;
4454+ }
4455+
4456+ void
4457+ // cppcheck-suppress unusedFunction
4458+ UNITY_SCOPE_DESTROY_FUNCTION(unity::scopes::ScopeBase* scope_base)
4459+ {
4460+ delete scope_base;
4461+ }
4462+}
4463
4464=== added file 'test/gtest/scopes/ResultCache/CacheScope.h'
4465--- test/gtest/scopes/ResultCache/CacheScope.h 1970-01-01 00:00:00 +0000
4466+++ test/gtest/scopes/ResultCache/CacheScope.h 2015-01-13 07:11:02 +0000
4467@@ -0,0 +1,41 @@
4468+/*
4469+ * Copyright (C) 2015 Canonical Ltd
4470+ *
4471+ * This program is free software: you can redistribute it and/or modify
4472+ * it under the terms of the GNU Lesser General Public License version 3 as
4473+ * published by the Free Software Foundation.
4474+ *
4475+ * This program is distributed in the hope that it will be useful,
4476+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4477+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4478+ * GNU Lesser General Public License for more details.
4479+ *
4480+ * You should have received a copy of the GNU Lesser General Public License
4481+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4482+ *
4483+ * Authored by: Michi Henning <michi.henning@canonical.com>
4484+ */
4485+
4486+#pragma once
4487+
4488+#include <unity/scopes/ScopeBase.h>
4489+
4490+class CacheScope : public unity::scopes::ScopeBase
4491+{
4492+public:
4493+ virtual void start(std::string const&) override;
4494+
4495+ virtual void stop() override;
4496+
4497+ virtual void run() override;
4498+
4499+ virtual unity::scopes::SearchQueryBase::UPtr search(unity::scopes::CannedQuery const &,
4500+ unity::scopes::SearchMetadata const &) override;
4501+
4502+ virtual unity::scopes::PreviewQueryBase::UPtr preview(unity::scopes::Result const&,
4503+ unity::scopes::ActionMetadata const &) override;
4504+
4505+private:
4506+ std::string id_;
4507+ std::mutex mutex_;
4508+};
4509
4510=== added file 'test/gtest/scopes/ResultCache/CacheScope.ini.in'
4511--- test/gtest/scopes/ResultCache/CacheScope.ini.in 1970-01-01 00:00:00 +0000
4512+++ test/gtest/scopes/ResultCache/CacheScope.ini.in 2015-01-13 07:11:02 +0000
4513@@ -0,0 +1,4 @@
4514+[ScopeConfig]
4515+DisplayName = CacheScope
4516+Description = Scope that pushes cached results for surfacing query
4517+Author = Michi
4518
4519=== added file 'test/gtest/scopes/ResultCache/ResultCache_test.cpp'
4520--- test/gtest/scopes/ResultCache/ResultCache_test.cpp 1970-01-01 00:00:00 +0000
4521+++ test/gtest/scopes/ResultCache/ResultCache_test.cpp 2015-01-13 07:11:02 +0000
4522@@ -0,0 +1,343 @@
4523+/*
4524+ * Copyright (C) 2015 Canonical Ltd
4525+ *
4526+ * This program is free software: you can redistribute it and/or modify
4527+ * it under the terms of the GNU Lesser General Public License version 3 as
4528+ * published by the Free Software Foundation.
4529+ *
4530+ * This program is distributed in the hope that it will be useful,
4531+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
4532+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
4533+ * GNU Lesser General Public License for more details.
4534+ *
4535+ * You should have received a copy of the GNU Lesser General Public License
4536+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
4537+ *
4538+ * Authored by: Michi Henning <michi.henning@canonical.com>
4539+ */
4540+
4541+#include <unity/scopes/CategorisedResult.h>
4542+#include <unity/scopes/internal/RegistryObject.h>
4543+#include <unity/scopes/internal/RuntimeImpl.h>
4544+#include <unity/scopes/internal/ScopeImpl.h>
4545+
4546+#include <boost/filesystem.hpp>
4547+#include <gtest/gtest.h>
4548+
4549+#include "CacheScope.h"
4550+
4551+using namespace std;
4552+using namespace unity::scopes;
4553+using namespace unity::scopes::internal;
4554+
4555+class Receiver : public SearchListenerBase
4556+{
4557+public:
4558+ Receiver()
4559+ : query_complete_(false)
4560+ {
4561+ }
4562+
4563+ virtual void push(Department::SCPtr const& parent) override
4564+ {
4565+ lock_guard<mutex> lock(mutex_);
4566+ dept_ = parent;
4567+ }
4568+
4569+ virtual void push(CategorisedResult result) override
4570+ {
4571+ lock_guard<mutex> lock(mutex_);
4572+ result_ = make_shared<CategorisedResult>(result);
4573+ }
4574+
4575+ virtual void finished(CompletionDetails const& details) override
4576+ {
4577+ EXPECT_EQ(CompletionDetails::OK, details.status()) << details.message();
4578+ lock_guard<mutex> lock(mutex_);
4579+ query_complete_ = true;
4580+ cond_.notify_one();
4581+ }
4582+
4583+ void wait_until_finished()
4584+ {
4585+ unique_lock<mutex> lock(mutex_);
4586+ cond_.wait(lock, [this] { return this->query_complete_; });
4587+ query_complete_ = false;
4588+ }
4589+
4590+ Department::SCPtr dept() const
4591+ {
4592+ lock_guard<mutex> lock(mutex_);
4593+ return dept_;
4594+ }
4595+
4596+ CategorisedResult::SCPtr result() const
4597+ {
4598+ lock_guard<mutex> lock(mutex_);
4599+ return result_;
4600+ }
4601+
4602+private:
4603+ Department::SCPtr dept_;
4604+ CategorisedResult::SCPtr result_;
4605+ bool query_complete_;
4606+ mutable mutex mutex_;
4607+ condition_variable cond_;
4608+};
4609+
4610+class CacheScopeTest : public ::testing::Test
4611+{
4612+public:
4613+ CacheScopeTest()
4614+ {
4615+ runtime_ = Runtime::create(TEST_RUNTIME_FILE);
4616+ auto reg = runtime_->registry();
4617+ auto meta = reg->get_metadata("CacheScope");
4618+ scope_ = meta.proxy();
4619+ meta = reg->get_metadata("AlwaysPushFromCacheScope");
4620+ always_push_from_cache_scope_ = meta.proxy();
4621+ }
4622+
4623+ ScopeProxy scope() const
4624+ {
4625+ return scope_;
4626+ }
4627+
4628+ ScopeProxy always_push_from_cache_scope() const
4629+ {
4630+ return always_push_from_cache_scope_;
4631+ }
4632+
4633+private:
4634+ Runtime::UPtr runtime_;
4635+ ScopeProxy scope_;
4636+ ScopeProxy always_push_from_cache_scope_;
4637+};
4638+
4639+TEST_F(CacheScopeTest, push_from_cache_without_cache_file)
4640+{
4641+ ::unlink(TEST_RUNTIME_PATH "/unconfined/AlwaysPushFromCacheScope/.surfacing_cache");
4642+ auto receiver = make_shared<Receiver>();
4643+ always_push_from_cache_scope()->search("", SearchMetadata("unused", "unused"), receiver);
4644+ receiver->wait_until_finished();
4645+
4646+ auto r = receiver->result();
4647+ EXPECT_EQ(r, nullptr);
4648+}
4649+
4650+TEST_F(CacheScopeTest, non_surfacing_query)
4651+{
4652+ ::chmod(TEST_RUNTIME_PATH "/unconfined/CacheScope", 0700);
4653+ ::unlink(TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache");
4654+ auto receiver = make_shared<Receiver>();
4655+ scope()->search("some query", SearchMetadata("unused", "unused"), receiver);
4656+ receiver->wait_until_finished();
4657+
4658+ auto r = receiver->result();
4659+ EXPECT_EQ(r->title(), "some query");
4660+ auto d = receiver->dept();
4661+ EXPECT_EQ(d->id(), "");
4662+ auto sd = *d->subdepartments().begin();
4663+ EXPECT_EQ(sd->id(), "subsome query");
4664+
4665+ // Non-empty query, so there must be no cache file.
4666+ boost::system::error_code ec;
4667+ EXPECT_FALSE(boost::filesystem::exists(TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache", ec));
4668+}
4669+
4670+TEST_F(CacheScopeTest, surfacing_query)
4671+{
4672+ ::unlink(TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache");
4673+ auto receiver = make_shared<Receiver>();
4674+ scope()->search("", SearchMetadata("unused", "unused"), receiver);
4675+ receiver->wait_until_finished();
4676+
4677+ auto r = receiver->result();
4678+ EXPECT_EQ(r->title(), "");
4679+ auto d = receiver->dept();
4680+ EXPECT_EQ(d->id(), "");
4681+ auto sd = *d->subdepartments().begin();
4682+ EXPECT_EQ(sd->id(), "sub");
4683+
4684+ // Empty query, so there must be a cache file.
4685+ boost::system::error_code ec;
4686+ EXPECT_TRUE(boost::filesystem::exists(TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache", ec));
4687+}
4688+
4689+// Run another non-surfacing query before checking that the cache contains the
4690+// results of the last surfacing query.
4691+
4692+TEST_F(CacheScopeTest, non_surfacing_query2)
4693+{
4694+ auto receiver = make_shared<Receiver>();
4695+ scope()->search("some other query", SearchMetadata("unused", "unused"), receiver);
4696+ receiver->wait_until_finished();
4697+
4698+ auto r = receiver->result();
4699+ EXPECT_EQ(r->title(), "some other query");
4700+ auto d = receiver->dept();
4701+ EXPECT_EQ(d->id(), "");
4702+ auto sd = *d->subdepartments().begin();
4703+ EXPECT_EQ(sd->id(), "subsome other query");
4704+
4705+ // Cache file must still be there.
4706+ boost::system::error_code ec;
4707+ EXPECT_TRUE(boost::filesystem::exists(TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache", ec));
4708+}
4709+
4710+TEST_F(CacheScopeTest, push_from_cache)
4711+{
4712+ auto receiver = make_shared<Receiver>();
4713+ scope()->search("", SearchMetadata("unused", "unused"), receiver);
4714+ receiver->wait_until_finished();
4715+
4716+ auto r = receiver->result();
4717+ EXPECT_EQ(r->title(), "");
4718+ auto d = receiver->dept();
4719+ EXPECT_EQ(d->id(), "");
4720+ auto sd = *d->subdepartments().begin();
4721+ EXPECT_EQ(sd->id(), "sub");
4722+
4723+ // Cache file must still be there.
4724+ boost::system::error_code ec;
4725+ EXPECT_TRUE(boost::filesystem::exists(TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache", ec));
4726+}
4727+
4728+TEST_F(CacheScopeTest, push_non_empty_from_cache)
4729+{
4730+ auto receiver = make_shared<Receiver>();
4731+ scope()->search("non-empty from cache", SearchMetadata("unused", "unused"), receiver);
4732+ receiver->wait_until_finished();
4733+
4734+ // Cache file must still be there.
4735+ boost::system::error_code ec;
4736+ EXPECT_TRUE(boost::filesystem::exists(TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache", ec));
4737+}
4738+
4739+TEST_F(CacheScopeTest, write_failure)
4740+{
4741+ ::unlink(TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache");
4742+ ::chmod(TEST_RUNTIME_PATH "/unconfined/CacheScope", 0);
4743+ auto receiver = make_shared<Receiver>();
4744+ scope()->search("", SearchMetadata("unused", "unused"), receiver);
4745+ receiver->wait_until_finished();
4746+
4747+ // Empty query, but cache file could not be created
4748+ ::chmod(TEST_RUNTIME_PATH "/unconfined/CacheScope", 0700);
4749+ boost::system::error_code ec;
4750+ EXPECT_FALSE(boost::filesystem::exists(TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache", ec));
4751+}
4752+
4753+TEST_F(CacheScopeTest, surfacing_query_2)
4754+{
4755+ auto receiver = make_shared<Receiver>();
4756+ scope()->search("", SearchMetadata("unused", "unused"), receiver);
4757+ receiver->wait_until_finished();
4758+
4759+ auto r = receiver->result();
4760+ EXPECT_EQ(r->title(), "");
4761+ auto d = receiver->dept();
4762+ EXPECT_EQ(d->id(), "");
4763+ auto sd = *d->subdepartments().begin();
4764+ EXPECT_EQ(sd->id(), "sub");
4765+
4766+ // New cache file must have been created
4767+ boost::system::error_code ec;
4768+ EXPECT_TRUE(boost::filesystem::exists(TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache", ec));
4769+}
4770+
4771+TEST_F(CacheScopeTest, read_failure)
4772+{
4773+ ::chmod(TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache", 0);
4774+ auto receiver = make_shared<Receiver>();
4775+ scope()->search("", SearchMetadata("unused", "unused"), receiver);
4776+ receiver->wait_until_finished();
4777+ EXPECT_EQ(receiver->result(), nullptr);
4778+ ::chmod(TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache", 0600);
4779+
4780+ // Cache file must still be there, but read will have failed.
4781+ boost::system::error_code ec;
4782+ EXPECT_TRUE(boost::filesystem::exists(TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache", ec));
4783+}
4784+
4785+// Stop warnings about unused return value from system()
4786+
4787+#pragma GCC diagnostic push
4788+#pragma GCC diagnostic ignored "-Wunused-result"
4789+
4790+TEST_F(CacheScopeTest, missing_departments)
4791+{
4792+ // Get coverage on missing departments entry
4793+ system("cp " TEST_SOURCE_PATH "/no_dept_cache " TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache");
4794+ auto receiver = make_shared<Receiver>();
4795+ scope()->search("", SearchMetadata("unused", "unused"), receiver);
4796+ receiver->wait_until_finished();
4797+ EXPECT_EQ(receiver->result(), nullptr);
4798+
4799+ // Cache file must still be there, but decode will have failed.
4800+ boost::system::error_code ec;
4801+ EXPECT_TRUE(boost::filesystem::exists(TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache", ec));
4802+}
4803+
4804+TEST_F(CacheScopeTest, missing_categories)
4805+{
4806+ // Get coverage on missing categories entry
4807+ system("cp " TEST_SOURCE_PATH "/no_cat_cache " TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache");
4808+ auto receiver = make_shared<Receiver>();
4809+ scope()->search("", SearchMetadata("unused", "unused"), receiver);
4810+ receiver->wait_until_finished();
4811+ EXPECT_EQ(receiver->result(), nullptr);
4812+
4813+ // Cache file must still be there, but decode will have failed.
4814+ boost::system::error_code ec;
4815+ EXPECT_TRUE(boost::filesystem::exists(TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache", ec));
4816+}
4817+
4818+TEST_F(CacheScopeTest, missing_results)
4819+{
4820+ // Get coverage on missing results entry
4821+ system("cp " TEST_SOURCE_PATH "/no_results_cache " TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache");
4822+ auto receiver = make_shared<Receiver>();
4823+ scope()->search("", SearchMetadata("unused", "unused"), receiver);
4824+ receiver->wait_until_finished();
4825+ EXPECT_EQ(receiver->result(), nullptr);
4826+
4827+ // Cache file must still be there, but decode will have failed.
4828+ boost::system::error_code ec;
4829+ EXPECT_TRUE(boost::filesystem::exists(TEST_RUNTIME_PATH "/unconfined/CacheScope/.surfacing_cache", ec));
4830+}
4831+
4832+#pragma GCC diagnostic pop
4833+
4834+int main(int argc, char **argv)
4835+{
4836+ ::testing::InitGoogleTest(&argc, argv);
4837+
4838+ int rc = 0;
4839+
4840+ // Set the "TEST_DESKTOP_FILES_DIR" env var before forking as not to create desktop files in ~/.local
4841+ putenv(const_cast<char*>("TEST_DESKTOP_FILES_DIR=" TEST_RUNTIME_PATH));
4842+
4843+ auto rpid = fork();
4844+ if (rpid == 0)
4845+ {
4846+ const char* const args[] = {"scoperegistry [CacheScope_test]", TEST_RUNTIME_FILE, nullptr};
4847+ if (execv(TEST_REGISTRY_PATH "/scoperegistry", const_cast<char* const*>(args)) < 0)
4848+ {
4849+ perror("Error starting scoperegistry:");
4850+ }
4851+ return 1;
4852+ }
4853+ else if (rpid > 0)
4854+ {
4855+ rc = RUN_ALL_TESTS();
4856+ kill(rpid, SIGTERM);
4857+ waitpid(rpid, nullptr, 0);
4858+ }
4859+ else
4860+ {
4861+ perror("Failed to fork:");
4862+ }
4863+
4864+ return rc;
4865+}
4866
4867=== added file 'test/gtest/scopes/ResultCache/Runtime.ini.in'
4868--- test/gtest/scopes/ResultCache/Runtime.ini.in 1970-01-01 00:00:00 +0000
4869+++ test/gtest/scopes/ResultCache/Runtime.ini.in 2015-01-13 07:11:02 +0000
4870@@ -0,0 +1,8 @@
4871+[Runtime]
4872+Registry.Identity = TestRegistry
4873+Registry.ConfigFile = @CMAKE_CURRENT_BINARY_DIR@/TestRegistry.ini
4874+Default.Middleware = Zmq
4875+Zmq.ConfigFile = @CMAKE_CURRENT_BINARY_DIR@/Zmq.ini
4876+Smartscopes.Registry.Identity =
4877+CacheDir=@CMAKE_CURRENT_BINARY_DIR@
4878+LogDir=
4879
4880=== added file 'test/gtest/scopes/ResultCache/TestRegistry.ini.in'
4881--- test/gtest/scopes/ResultCache/TestRegistry.ini.in 1970-01-01 00:00:00 +0000
4882+++ test/gtest/scopes/ResultCache/TestRegistry.ini.in 2015-01-13 07:11:02 +0000
4883@@ -0,0 +1,7 @@
4884+[Registry]
4885+Middleware = Zmq
4886+Zmq.ConfigFile = @CMAKE_CURRENT_BINARY_DIR@/Zmq.ini
4887+Scope.InstallDir = @CMAKE_CURRENT_BINARY_DIR@/scopes
4888+OEM.InstallDir = /unused
4889+Click.InstallDir = @CMAKE_CURRENT_BINARY_DIR@/click
4890+Scoperunner.Path = @PROJECT_BINARY_DIR@/scoperunner/scoperunner
4891
4892=== added file 'test/gtest/scopes/ResultCache/Zmq.ini.in'
4893--- test/gtest/scopes/ResultCache/Zmq.ini.in 1970-01-01 00:00:00 +0000
4894+++ test/gtest/scopes/ResultCache/Zmq.ini.in 2015-01-13 07:11:02 +0000
4895@@ -0,0 +1,2 @@
4896+[Zmq]
4897+EndpointDir = /tmp
4898
4899=== added file 'test/gtest/scopes/ResultCache/no_cat_cache'
4900--- test/gtest/scopes/ResultCache/no_cat_cache 1970-01-01 00:00:00 +0000
4901+++ test/gtest/scopes/ResultCache/no_cat_cache 2015-01-13 07:11:02 +0000
4902@@ -0,0 +1,1 @@
4903+{"departments":{"departments":[{"label":"Sub","query":{"department_id":"sub","filter_state":{},"query_string":"","scope":"CacheScope"}}],"label":"Top","query":{"department_id":"","filter_state":{},"query_string":"","scope":"CacheScope"}},"results":[{"attrs":{"title":"","uri":"uri"},"internal":{"cat_id":"CacheScope"}}]}
4904
4905=== added file 'test/gtest/scopes/ResultCache/no_dept_cache'
4906--- test/gtest/scopes/ResultCache/no_dept_cache 1970-01-01 00:00:00 +0000
4907+++ test/gtest/scopes/ResultCache/no_dept_cache 2015-01-13 07:11:02 +0000
4908@@ -0,0 +1,1 @@
4909+{"categories":[{"icon":"","id":"CacheScope","renderer_template":"\n {\n \"schema-version\":1,\n \"template\":\n {\n \"category-layout\":\"grid\"\n },\n \"components\":\n {\n \"title\":\"title\",\n \"art\":\"art\"\n }\n }\n ","title":""}],"results":[{"attrs":{"title":"","uri":"uri"},"internal":{"cat_id":"CacheScope"}}]}
4910
4911=== added file 'test/gtest/scopes/ResultCache/no_results_cache'
4912--- test/gtest/scopes/ResultCache/no_results_cache 1970-01-01 00:00:00 +0000
4913+++ test/gtest/scopes/ResultCache/no_results_cache 2015-01-13 07:11:02 +0000
4914@@ -0,0 +1,1 @@
4915+{"categories":[{"icon":"","id":"CacheScope","renderer_template":"\n {\n \"schema-version\":1,\n \"template\":\n {\n \"category-layout\":\"grid\"\n },\n \"components\":\n {\n \"title\":\"title\",\n \"art\":\"art\"\n }\n }\n ","title":""}],"departments":{"departments":[{"label":"Sub","query":{"department_id":"sub","filter_state":{},"query_string":"","scope":"CacheScope"}}],"label":"Top","query":{"department_id":"","filter_state":{},"query_string":"","scope":"CacheScope"}}}
4916
4917=== added directory 'test/gtest/scopes/ResultCache/unconfined'
4918=== added directory 'test/gtest/scopes/ResultCache/unconfined/CacheScope'
4919=== modified file 'test/gtest/scopes/Runtime/Runtime.ini.in'
4920--- test/gtest/scopes/Runtime/Runtime.ini.in 2014-07-18 07:30:20 +0000
4921+++ test/gtest/scopes/Runtime/Runtime.ini.in 2015-01-13 07:11:02 +0000
4922@@ -3,3 +3,4 @@
4923 Registry.ConfigFile = Registry.ini
4924 Default.Middleware = Zmq
4925 Zmq.ConfigFile = Zmq.ini
4926+LogDir=
4927
4928=== modified file 'test/gtest/scopes/Runtime/Runtime_test.cpp'
4929--- test/gtest/scopes/Runtime/Runtime_test.cpp 2014-12-05 02:39:39 +0000
4930+++ test/gtest/scopes/Runtime/Runtime_test.cpp 2015-01-13 07:11:02 +0000
4931@@ -309,7 +309,7 @@
4932 auto mw = rt->factory()->create("TestScope", "Zmq", "Zmq.ini");
4933 mw->start();
4934 auto proxy = mw->create_scope_proxy("TestScope");
4935- auto scope = internal::ScopeImpl::create(proxy, rt.get(), "TestScope");
4936+ auto scope = internal::ScopeImpl::create(proxy, "TestScope");
4937
4938 auto receiver = make_shared<Receiver>();
4939 auto ctrl = scope->search("test", SearchMetadata("en", "phone"), receiver);
4940@@ -324,7 +324,7 @@
4941 mw->start();
4942
4943 auto proxy = mw->create_scope_proxy("TestScope");
4944- auto scope = internal::ScopeImpl::create(proxy, rt.get(), "TestScope");
4945+ auto scope = internal::ScopeImpl::create(proxy, "TestScope");
4946
4947 auto receiver = make_shared<Receiver>();
4948 auto ctrl = scope->search("test", SearchMetadata("en", "phone"), receiver);
4949@@ -367,7 +367,7 @@
4950 auto mw = rt->factory()->create("TestScope", "Zmq", "Zmq.ini");
4951 mw->start();
4952 auto proxy = mw->create_scope_proxy("TestScope");
4953- auto scope = internal::ScopeImpl::create(proxy, rt.get(), "TestScope");
4954+ auto scope = internal::ScopeImpl::create(proxy, "TestScope");
4955
4956 // run a query first, so we have a result to preview
4957 auto receiver = make_shared<Receiver>();
4958@@ -396,7 +396,7 @@
4959 auto mw = rt->factory()->create("PusherScope", "Zmq", "Zmq.ini");
4960 mw->start();
4961 auto proxy = mw->create_scope_proxy("PusherScope");
4962- auto scope = internal::ScopeImpl::create(proxy, rt.get(), "PusherScope");
4963+ auto scope = internal::ScopeImpl::create(proxy, "PusherScope");
4964
4965 // Run a query with unlimited cardinality. We check that the
4966 // scope returns 100 results.
4967@@ -453,7 +453,7 @@
4968 auto mw = rt->factory()->create("SlowCreateScope", "Zmq", "Zmq.ini");
4969 mw->start();
4970 auto proxy = mw->create_scope_proxy("SlowCreateScope");
4971- auto scope = internal::ScopeImpl::create(proxy, rt.get(), "SlowCreateScope");
4972+ auto scope = internal::ScopeImpl::create(proxy, "SlowCreateScope");
4973
4974 // Allow some time for the middleware to start up.
4975 this_thread::sleep_for(chrono::milliseconds(200));
4976
4977=== modified file 'test/gtest/scopes/internal/ResultReplyObject/Runtime.ini.in'
4978--- test/gtest/scopes/internal/ResultReplyObject/Runtime.ini.in 2014-02-24 14:56:26 +0000
4979+++ test/gtest/scopes/internal/ResultReplyObject/Runtime.ini.in 2015-01-13 07:11:02 +0000
4980@@ -3,3 +3,4 @@
4981 Registry.ConfigFile = Registry.ini
4982 Default.Middleware = Zmq
4983 Zmq.ConfigFile = Zmq.ini
4984+LogDir=
4985
4986=== added file 'test/gtest/scopes/internal/RuntimeConfig/BadLogDirSize.ini'
4987--- test/gtest/scopes/internal/RuntimeConfig/BadLogDirSize.ini 1970-01-01 00:00:00 +0000
4988+++ test/gtest/scopes/internal/RuntimeConfig/BadLogDirSize.ini 2015-01-13 07:11:02 +0000
4989@@ -0,0 +1,7 @@
4990+[Runtime]
4991+CacheDir = cachedir
4992+AppDir = appdir
4993+ConfigDir = configdir
4994+LogDir = logdir
4995+Log.MaxFileSize = 2048
4996+Log.MaxDirSize = 1024
4997
4998=== added file 'test/gtest/scopes/internal/RuntimeConfig/BadLogFileSize.ini'
4999--- test/gtest/scopes/internal/RuntimeConfig/BadLogFileSize.ini 1970-01-01 00:00:00 +0000
5000+++ test/gtest/scopes/internal/RuntimeConfig/BadLogFileSize.ini 2015-01-13 07:11:02 +0000
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: