Merge lp:~knitzsche/scope-aggregator/fixes-fallback-bug-1599948 into lp:scope-aggregator

Proposed by Kyle Nitzsche
Status: Merged
Approved by: Kyle Nitzsche
Approved revision: 170
Merge reported by: Kyle Nitzsche
Merged at revision: not available
Proposed branch: lp:~knitzsche/scope-aggregator/fixes-fallback-bug-1599948
Merge into: lp:scope-aggregator
Diff against target: 109 lines (+21/-14)
3 files modified
CMakeLists.txt (+1/-1)
src/query.cpp (+19/-13)
src/utils.cpp (+1/-0)
To merge this branch: bzr merge lp:~knitzsche/scope-aggregator/fixes-fallback-bug-1599948
Reviewer Review Type Date Requested Status
Zhang Enwei (community) Approve
Penk Chen Pending
Gary.Wang Pending
Review via email: mp+299481@code.launchpad.net

Description of the change

Fixes the fallback mechanism through which the aggregator scope
can attempt to find, for example, art in other result fields, for
example mascot, or emblem. There was an exception when a result
did not contain the primary field because in some cases the code
tried to access a field that did not exist.

This problem causes exceptions when News scope aggregates El Pais
(which sometimes lacks expected attributes) and Yahoo, which now
always lacks "art", "mascot" and "emblem" -- see:
https://bugs.launchpad.net/news-scope/+bug/1600026

To post a comment you must log in.
Revision history for this message
Kyle Nitzsche (knitzsche) wrote :

FYI: I am adding googletest unit tests to scope-aggregator and I will definitely add tests for fallback mechanism.

Revision history for this message
Zhang Enwei (zhangew401) wrote :

Look good to me

review: Approve
170. By Kyle Nitzsche

When testing photos scope I found an issue that this commit fixes.

Please review. The key change is line 1192.

DETAILS

The issue I noticed when testing this MP in photos-scope is that the art for
Douban LOGIN result did not display in photos agg scope.

I found that the fallback code (check_result_fallbacks()) was not called
for Duoban in the login case.

The general case I found is: For scopes that are declared in child_scopes.json
using the "scope" key, the check_results_callbacks() method was not called.

(Please note that fallbacks code/feature is only currently implemented
for scopes that use a renderer defined in common_templates.)

Teseting. Modify photos scope child_scopes.json to only this for Duoban:

        "scope": {
            "_category_title": "My Douban Photos",
            "id": "com.canonical.scopes.douban_doubanalbum",
            "local_id": "douban",
            "result_category_id_to_common_template": [
              {
                "result_category_id": "login",
                "common_template": "not_logged_in"
              }
            ],
            "renderer_common_id": "normal_renderer"
        }

This ^ means:
 * if Douban result category is "login": use common_template "not logged_in".
    This template uses a fallback:
            "id": "not_logged_in",
            "fallbacks":
            [
                {
                    "key": "mascot",
                    "fields":
                    [
                        {"field": "mascot"},
                        {"field": "art"}
                    ]
                }
            ],
    [...]
    Result is that Douban's login result which provides "art" is converted to
    "mascot".
* A result with any other category uses "normal_renderer". This does not use a
  fallback and expects the result to contain 'art".

Revision history for this message
Kyle Nitzsche (knitzsche) wrote :

Note that the douban login art previously did not display in photos agg, so this is not a regression caused by the MP. Good time to fix it though.

Revision history for this message
Zhang Enwei (zhangew401) wrote :

LGTM

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2016-06-29 10:29:37 +0000
+++ CMakeLists.txt 2016-07-12 17:15:04 +0000
@@ -1,4 +1,4 @@
1set(VERSION "4.8")1set(VERSION "4.9")
22
3# Supress qDebug() output3# Supress qDebug() output
4ADD_DEFINITIONS( -DQT_NO_DEBUG_OUTPUT )4ADD_DEFINITIONS( -DQT_NO_DEBUG_OUTPUT )
55
=== modified file 'src/query.cpp'
--- src/query.cpp 2016-06-29 10:29:37 +0000
+++ src/query.cpp 2016-07-12 17:15:04 +0000
@@ -392,15 +392,19 @@
392 const auto & map = *common_templates_fallbacks[common_id];392 const auto & map = *common_templates_fallbacks[common_id];
393 for(auto iter = map.begin(); iter != map.end(); ++iter)393 for(auto iter = map.begin(); iter != map.end(); ++iter)
394 {394 {
395 qDebug() << "==== check FALLB first: " << qstr(iter->first);395 qDebug() << "==== check FALLB field to populate: " << qstr(iter->first);
396 if (res.contains(iter->first))
397 {
398 qDebug() << "=== check FALLB. res has field: " << qstr(iter->first);
399 return;
400 }
396 for (const auto & field : iter->second)401 for (const auto & field : iter->second)
397 {402 {
398 qDebug() << "==== check FALLB field: " << qstr(field);403 qDebug() << "==== check FALLB field exists: " << qstr(field);
399 if (res[iter->first].get_string().empty())404 if (res.contains(field))
400 {405 {
401 qDebug() << "==== check FALLB first is empty: " << qstr(res[iter->first].get_string());406 res[iter->first] = res[field].get_string();
402 if (res.contains(field))407 return;
403 res[iter->first] = res[field];
404 }408 }
405 }409 }
406 }410 }
@@ -557,7 +561,8 @@
557561
558 // save bits of incoming result562 // save bits of incoming result
559 std::string inc_res_cat_id = res.category()->id();563 std::string inc_res_cat_id = res.category()->id();
560 us::Category::SCPtr res_cat = res.category();564 qDebug() <<"=== incoming result cat rdr: " << qstr(res.category()->renderer_template().data());
565 qDebug() <<"=== incoming result: " << qstr(us::Variant(res.serialize()).serialize_json());
561 std::string inc_res_cat_title = res.category()->title();566 std::string inc_res_cat_title = res.category()->title();
562567
563 qDebug() << "==== RESULT scope: " << qstr(scope->id());568 qDebug() << "==== RESULT scope: " << qstr(scope->id());
@@ -1175,14 +1180,16 @@
1175 // if needed, get renderer from result_category_to_common_template1180 // if needed, get renderer from result_category_to_common_template
1176 if (common_templates.find(child_scopes_m[scope->local_id()]->result_category_id_to_common_template[res.category()->id()]) != common_templates.end())1181 if (common_templates.find(child_scopes_m[scope->local_id()]->result_category_id_to_common_template[res.category()->id()]) != common_templates.end())
1177 {1182 {
1178 qDebug() << "==== DECLARED. category to renderer";1183 qDebug() << "==== DECLARED. current category:" << qstr(res.category()->id());
1179 std::string common_template_id = child_scopes_m[scope->local_id()]->result_category_id_to_common_template[res.category()->id()];1184 std::string common_template_id = child_scopes_m[scope->local_id()]->result_category_id_to_common_template[res.category()->id()];
1185 qDebug() << "==== DECLARED. using common_template_id: " << qstr(common_template_id);
1180 std::string cat_id = common_template_id + ":" + scope->local_id() + cat_title;1186 std::string cat_id = common_template_id + ":" + scope->local_id() + cat_title;
11811187
1182 // if the common category has not yet been registered, register it1188 // if the common category has not yet been registered, register it
1183 if (!upstream_reply->lookup_category(cat_id))1189 if (!upstream_reply->lookup_category(cat_id))
1184 {1190 {
1185 std::string template_to_use = common_templates[child_scopes_m[scope->local_id()]->result_category_id_to_common_template[res.category()->id()]];1191 std::string template_to_use = common_templates[child_scopes_m[scope->local_id()]->result_category_id_to_common_template[res.category()->id()]];
1192 check_result_fallbacks(res, common_template_id);
1186 if (scope->category_link_to_child())1193 if (scope->category_link_to_child())
1187 {1194 {
1188 if (!upstream_reply->lookup_category(cat_id))1195 if (!upstream_reply->lookup_category(cat_id))
@@ -1287,7 +1294,7 @@
1287 for (size_t i = 0; i < replies.size(); ++i) {1294 for (size_t i = 0; i < replies.size(); ++i) {
1288 us::SearchMetadata metadata(search_metadata());1295 us::SearchMetadata metadata(search_metadata());
1289 std::string locID = scopes_m_int_localId[i];1296 std::string locID = scopes_m_int_localId[i];
1290 qDebug() << "==== locID: " << QString::fromStdString(locID);1297 qDebug() << "==== subsearch locID: " << qstr(locID);
1291 auto scope = scopes_m[locID];1298 auto scope = scopes_m[locID];
12921299
1293 if (scope->keyword_scope())1300 if (scope->keyword_scope())
@@ -1317,9 +1324,7 @@
1317 metadata.set_cardinality( scope->cardinality() );1324 metadata.set_cardinality( scope->cardinality() );
1318 }1325 }
13191326
13201327 metadata.set_hint(scope->id(), us::Variant("valueMeansNothing"));
1321 qDebug() << "===- LOCAL_ID: " << qstr(scope->local_id());
1322 metadata.set_hint(scope->local_id(), us::Variant("valueMeansNothing"));
13231328
1324 // dispatch subsearches differently depending on whether is keyword or declared scope1329 // dispatch subsearches differently depending on whether is keyword or declared scope
1325 qDebug() << "==== QUERY STRING: " << QString::fromStdString(query_string);1330 qDebug() << "==== QUERY STRING: " << QString::fromStdString(query_string);
@@ -1403,7 +1408,8 @@
1403 adj_qry,1408 adj_qry,
1404 scope->child_department(),1409 scope->child_department(),
1405 us::FilterState(),1410 us::FilterState(),
1406 metadata, replies[i]1411 metadata,
1412 replies[i]
1407 );1413 );
1408 break;1414 break;
1409 }1415 }
14101416
=== modified file 'src/utils.cpp'
--- src/utils.cpp 2016-06-29 10:29:37 +0000
+++ src/utils.cpp 2016-07-12 17:15:04 +0000
@@ -61,6 +61,7 @@
61{61{
62 if (root.contains(QStringLiteral("cardinality_settings")))62 if (root.contains(QStringLiteral("cardinality_settings")))
63 {63 {
64 setting_cardinalities.clear();
64 QJsonArray card_a = root[QStringLiteral("cardinality_settings")].toArray();65 QJsonArray card_a = root[QStringLiteral("cardinality_settings")].toArray();
65 for (const auto & item : card_a)66 for (const auto & item : card_a)
66 {67 {

Subscribers

People subscribed via source and target branches