Merge lp:~dobey/unity-scope-click/clicksnap into lp:unity-scope-click

Proposed by dobey
Status: Rejected
Rejected by: dobey
Proposed branch: lp:~dobey/unity-scope-click/clicksnap
Merge into: lp:unity-scope-click
Prerequisite: lp:~dobey/unity-scope-click/ual-apps
Diff against target: 1900 lines (+682/-390)
23 files modified
bin/CMakeLists.txt (+4/-1)
bin/install-helper (+9/-2)
bin/install-snap (+73/-0)
debian/control (+6/-3)
libclickscope/click/configuration.cpp (+13/-3)
libclickscope/click/configuration.h (+1/-0)
libclickscope/click/download-manager.cpp (+53/-83)
libclickscope/click/download-manager.h (+4/-8)
libclickscope/click/index.cpp (+60/-6)
libclickscope/click/index.h (+11/-2)
libclickscope/click/package.cpp (+4/-0)
libclickscope/click/package.h (+4/-0)
libclickscope/click/preview.cpp (+16/-5)
libclickscope/click/webclient.cpp (+26/-17)
libclickscope/click/webclient.h (+2/-0)
libclickscope/tests/mock_webclient.h (+11/-7)
libclickscope/tests/test_bootstrap.cpp (+2/-2)
libclickscope/tests/test_download_manager.cpp (+155/-127)
libclickscope/tests/test_index.cpp (+157/-91)
libclickscope/tests/test_pay.cpp (+13/-13)
libclickscope/tests/test_preview.cpp (+2/-2)
libclickscope/tests/test_reviews.cpp (+16/-16)
scope/clickstore/store-query.cpp (+40/-2)
To merge this branch: bzr merge lp:~dobey/unity-scope-click/clicksnap
Reviewer Review Type Date Requested Status
unity-api-1-bot continuous-integration Approve
Charles Kerr (community) Approve
Review via email: mp+303974@code.launchpad.net

This proposal supersedes a proposal from 2016-08-24.

Commit message

Initial support in store scope for searching and installing snaps.

To post a comment you must log in.
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:496
https://jenkins.canonical.com/unity-api-1/job/lp-unity-scope-click-ci/86/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build/470
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/476
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=vivid+overlay/381
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=xenial+overlay/381
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=yakkety/381
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/311
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/311/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/311
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/311/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/311
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/311/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/311
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/311/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/311
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/311/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/311
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/311/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/311
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/311/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/311
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/311/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/311
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/311/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-unity-scope-click-ci/86/rebuild

review: Approve (continuous-integration)
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote : Posted in a previous version of this proposal

PASSED: Continuous integration, rev:497
https://jenkins.canonical.com/unity-api-1/job/lp-unity-scope-click-ci/88/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build/474
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/480
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=vivid+overlay/385
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=xenial+overlay/385
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=yakkety/385
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/315
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/315/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/315
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/315/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/315
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/315/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/315
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/315/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/315
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/315/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/315
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/315/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/315
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/315/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/315
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/315/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/315
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/315/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-unity-scope-click-ci/88/rebuild

review: Approve (continuous-integration)
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

PASSED: Continuous integration, rev:497
https://jenkins.canonical.com/unity-api-1/job/lp-unity-scope-click-ci/89/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build/489
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/495
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=vivid+overlay/400
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=xenial+overlay/400
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=yakkety/400
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/330
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/330/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/330
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/330/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/330
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/330/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/330
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/330/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/330
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/330/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/330
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/330/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/330
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/330/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/330
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/330/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/330
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/330/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-unity-scope-click-ci/89/rebuild

review: Approve (continuous-integration)
498. By dobey

Update dependencies to allow either snaps or clicks to be supported.

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

FAILED: Continuous integration, rev:498
https://jenkins.canonical.com/unity-api-1/job/lp-unity-scope-click-ci/91/
Executed test runs:
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build/493/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/499
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=vivid+overlay/404
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=xenial+overlay/404
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-1-sourcepkg/release=yakkety/404
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/334
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/334/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/334
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/334/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/334
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/334/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/334
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/334/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/334
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/334/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/334
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/334/artifact/output/*zip*/output.zip
    FAILURE: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/334/console
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/334
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/334/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/334
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/334/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-unity-scope-click-ci/91/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Charles Kerr (charlesk) wrote :

Review pt. 1 of 2, comments inline. About to be in transit and will finish review afterwards

review: Needs Information
Revision history for this message
Charles Kerr (charlesk) wrote :

Review pt. 2 of 2 inline. No showstoppers but a few more questions/comments

review: Needs Information
Revision history for this message
Charles Kerr (charlesk) :
499. By dobey

Merge up chagnes from ual-apps.

500. By dobey

Collapse snapd.socket check to simplify function.

501. By dobey

Remove the extra check for downloads.size > 1, as it shouldn't happen.

502. By dobey

Some cleanup in download-manager.cpp per code review.

503. By dobey

Fixes to index.cpp per code review.

504. By dobey

Break up mock responseForReply per code review.

505. By dobey

Refactor index tests perh code review.

506. By dobey

Use const auto in for loops.

Revision history for this message
dobey (dobey) wrote :

On Sat, 2016-09-03 at 01:11 +0000, Charles Kerr wrote:
> (optional) when a function reaches two bool arguments it's a
> candidate for an options bitfield a la GBusNameOwnerFlags

This is somewhat temporary. When we only support snaps, this will get
factored back out, as we won't need to know if something is a snap or
not at that point, since we'll only support snaps.

> I get that this isn't a red or green line, but out of curiosity,
> what's the rationale for calling details_callback() twice like this?
> So that showing the rest of the information won't block on the
> screenshot download?

I think maybe you were tired when you read this? Those are two
different branches of an if statement. :)

> 1. Each of the new tests looks at something unique, but they also
> look at get_architecture and get_available_framemworks in exactly the
> same way without any apparent benefit from the duplication. Maybe
> that should be moved into its own test; or if it's necessary for each
> of these tests, at least extracted into a fixture method that all of
> these can call

Refactored this into two different fixture classes.

> (needinfo) Is this correct? Shouldn't we be checking pkg.name or
> pkg.alias for empty() instead of pkg.snap_id?

Did it this way because we specifically only want to use alias for
snaps, and I think there isn't quite any guarantee that alias will
always we empty for clicks. However, this is also quite temporary, as
when we only support snaps, we'll only use what is appropriate for
that, and not worry about supporting clicks.

> (needinfo) Capturing 'this' in lambdas-inside-lambdas is always
> dicey. Are we certain that the lifetime of 'this' is safe s.t. it can
> be used this way?

I think this is fine here, as the outer call returns a pointer which we
store in this's private data, and which when destroyed aborts the
network requests, should prevent the callbacks being called, as the
requests get aborted. There is theoretically a possible race here, but
this will also be reduced back to single level when we stop supporting
clicks.

Revision history for this message
dobey (dobey) wrote :

On Fri, 2016-09-02 at 21:21 +0000, Charles Kerr wrote:
> (bikeshed) IMO "return (retval == 0) && ((sb.st_mode & S_IFMT) ==
> S_IFSOCK));" is more readable as it boils the function down to a
> single exit point

Thought it might be useful to do something with errno at some point
when I wrote this, but it's not really important here, so changed this
to the simpler return anyway. :)

> (question) when writing code like this I've been favoring
> qPrintable(str) for terseness over QString::fromStdString(str). Other
> than code readability, is there any real difference / advantage to
> choosing one over the other?

I was formerly using str.c_str() in most places, but fromStdString()
seems more explicit, and it's consistent with the rest of the code here
for now. Ideally I think we should probably do something else to make
this more readable (and switch to the simple logging hack I wrote a
while back, at some point).

> (minor) QList.size() isn't guaranteed to be constant complexity and
> we call downloadss.size() a few lines above too, suggest a const
> temporary to hold the size
>
> (needinfo) How is this reached??

Just removed this extra if() here, as it should indeed never be
reached, and simpler code is better. This also reduces the calls to
size() to a single call.

> (needinfo / needs fixing) Isn't this a dangling pointer here as
> toUtf8() goes out-of-scope at the end of this line?
>

Not entirely sure of the semantics here and if it would be a dangling
pointer, but after looking at the code, it seems like using
toStdString() would be better anyway, so I've changed this code, and
the bit below it to use that instead.

> (bikeshed) c++11's nested list-initialization lets you do this really
> cleanly, something like

Right, but we're not initializing from an empty map here. We're taking
a const input, and need to insert additional items into it. So we need
to copy the old list, then add the new items. I don't think we can do
that with the braces initializer.

> Seems like 'description' deserves a line in an error log somewhere

Not sure why it wasn't, but fixed here and in the other method this was
copied from.

Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

PASSED: Continuous integration, rev:506
https://jenkins.canonical.com/unity-api-1/job/lp-unity-scope-click-ci/101/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build/600
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/606
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/430
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/430/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/430
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/430/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/430
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/430/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/430
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/430/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/430
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/430/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/430
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/430/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/430
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/430/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/430
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/430/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/430
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/430/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-unity-scope-click-ci/101/rebuild

review: Approve (continuous-integration)
507. By dobey

Want const references for the for loops here.

Revision history for this message
Charles Kerr (charlesk) wrote :

> I think maybe you were tired when you read this? Those are two different branches of an if statement. :)

d'oh!

Thanks for the rest of the fixes & answers. Overall, a nice branch

review: Approve
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :

PASSED: Continuous integration, rev:507
https://jenkins.canonical.com/unity-api-1/job/lp-unity-scope-click-ci/102/
Executed test runs:
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build/601
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-0-fetch/607
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/431
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=vivid+overlay/431/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/431
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=xenial+overlay/431/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/431
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=amd64,release=yakkety/431/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/431
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=vivid+overlay/431/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/431
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=xenial+overlay/431/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/431
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=armhf,release=yakkety/431/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/431
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=vivid+overlay/431/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/431
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=xenial+overlay/431/artifact/output/*zip*/output.zip
    SUCCESS: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/431
        deb: https://jenkins.canonical.com/unity-api-1/job/build-2-binpkg/arch=i386,release=yakkety/431/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://jenkins.canonical.com/unity-api-1/job/lp-unity-scope-click-ci/102/rebuild

review: Approve (continuous-integration)
508. By dobey

New script to download snap assertions and perform install

509. By dobey

Fix the snap script to do the right thing.
Add necessary dependencies for the script.

510. By dobey

Check that filename argument is non-empty before continuing.

511. By dobey

Check if name is alias instead of using snap_id to determine if snap.

512. By dobey

If frameworks list is empty send "none" instead of empty header.

513. By dobey

Use a bash function instead of variable for wget, to avoid weird escaping.

Unmerged revisions

513. By dobey

Use a bash function instead of variable for wget, to avoid weird escaping.

512. By dobey

If frameworks list is empty send "none" instead of empty header.

511. By dobey

Check if name is alias instead of using snap_id to determine if snap.

510. By dobey

Check that filename argument is non-empty before continuing.

509. By dobey

Fix the snap script to do the right thing.
Add necessary dependencies for the script.

508. By dobey

New script to download snap assertions and perform install

507. By dobey

Want const references for the for loops here.

506. By dobey

Use const auto in for loops.

505. By dobey

Refactor index tests perh code review.

504. By dobey

Break up mock responseForReply per code review.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/CMakeLists.txt'
2--- bin/CMakeLists.txt 2014-08-14 14:59:57 +0000
3+++ bin/CMakeLists.txt 2016-09-21 14:55:05 +0000
4@@ -1,1 +1,4 @@
5-install(PROGRAMS install-helper enable-purchases DESTINATION lib/unity-scope-click/)
6+install(
7+ PROGRAMS install-helper install-snap enable-purchases
8+ DESTINATION lib/unity-scope-click/
9+)
10
11=== modified file 'bin/install-helper'
12--- bin/install-helper 2014-06-20 05:09:01 +0000
13+++ bin/install-helper 2016-09-21 14:55:05 +0000
14@@ -1,6 +1,6 @@
15 #!/bin/bash
16 #
17-# Copyright (C) 2014 Canonical Ltd.
18+# Copyright (C) 2014-2016 Canonical Ltd.
19 #
20 # This program is free software: you can redistribute it and/or modify it
21 # under the terms of the GNU General Public License version 3, as published
22@@ -47,7 +47,14 @@
23
24 function install-package {
25 FILE_NAME="$1"
26- pkcon -p install-local "$FILE_NAME"
27+ FILE_TYPE="${FILE_NAME##*.}"
28+ if [ ${FILE_TYPE} = "click" ]; then
29+ pkcon -p install-local "${FILE_NAME}"
30+ else
31+ SCRIPT_PATH=`dirname $0`
32+ SNAP_SCRIPT="${SCRIPT_PATH}/install-snap"
33+ pkexec ${SNAP_SCRIPT} "${FILE_NAME}"
34+ fi
35 }
36
37 function app_id-from-package_name {
38
39=== added file 'bin/install-snap'
40--- bin/install-snap 1970-01-01 00:00:00 +0000
41+++ bin/install-snap 2016-09-21 14:55:05 +0000
42@@ -0,0 +1,73 @@
43+#!/bin/bash
44+#
45+# Copyright (C) 2016 Canonical Ltd.
46+#
47+# This program is free software: you can redistribute it and/or modify it
48+# under the terms of the GNU General Public License version 3, as published
49+# by the Free Software Foundation.
50+#
51+# This program is distributed in the hope that it will be useful, but
52+# WITHOUT ANY WARRANTY; without even the implied warranties of
53+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
54+# PURPOSE. See the GNU General Public License for more details.
55+#
56+# You should have received a copy of the GNU General Public License along
57+# with this program. If not, see <http://www.gnu.org/licenses/>.
58+#
59+# In addition, as a special exception, the copyright holders give
60+# permission to link the code of portions of this program with the
61+# OpenSSL library under certain conditions as described in each
62+# individual source file, and distribute linked combinations
63+# including the two.
64+# You must obey the GNU General Public License in all respects
65+# for all of the code used other than OpenSSL. If you modify
66+# file(s) with this exception, you may extend this exception to your
67+# version of the file(s), but you are not obligated to do so. If you
68+# do not wish to do so, delete this exception statement from your
69+# version. If you delete this exception statement from all source
70+# files in the program, then also delete it here.
71+#
72+
73+set -ex
74+
75+if [ -z "$1" ]; then
76+ echo "usage: install-snap <filename.snap>"
77+ exit -10
78+fi
79+
80+SNAP_FILE_NAME="$1"
81+SNAP_FILE=$(basename ${SNAP_FILE_NAME})
82+SNAP_REVID=${SNAP_FILE%%.*}
83+SNAP_ID=${SNAP_REVID%%_*}
84+SNAP_REV=${SNAP_REVID##*_}
85+
86+# We have to get not just the 384 hash, but a "snap-digest" for the snap.
87+# This is a base64-encoded binary hex of the sha3 384 hash
88+SNAP_SHA3SUM=$(sha3sum -a 384 ${SNAP_FILE_NAME} | cut -d ' ' -f1)
89+SNAP_B64SHA=$(echo ${SNAP_SHA3SUM} | python3 -c 'import sys, binascii, base64; print(base64.urlsafe_b64encode(binascii.a2b_hex((sys.stdin.readline().strip().encode("ASCII")))).decode("ASCII").rstrip("="))')
90+
91+
92+# Need to get the assertions to add to snapd
93+ASSERTIONS_BASE_URL="https://assertions.ubuntu.com/v1/assertions"
94+function download {
95+ wget --header "Accept: application/x.ubuntu.assertion" -O - $1 > $2
96+}
97+
98+# The '16' is hard-coded here for series. By the time it changes again, we
99+# should have switched to using snapd for everything anyway.
100+download "${ASSERTIONS_BASE_URL}/snap-declaration/16/${SNAP_ID}" "${SNAP_FILE_NAME}.snap-declaration"
101+download "${ASSERTIONS_BASE_URL}/snap-revision/${SNAP_B64SHA}" "${SNAP_FILE_NAME}.snap-revision"
102+
103+# We have to get the publisher-id to get the account assertion for install
104+AUTHOR_ID=$(grep "publisher-id:" ${SNAP_FILE_NAME}.snap-declaration | cut -d ' ' -f2)
105+download "${ASSERTIONS_BASE_URL}/account/${AUTHOR_ID}" "${SNAP_FILE_NAME}.account"
106+
107+# snap exits with error if assertion already exists, so must ignore errors :-/
108+snap ack "${SNAP_FILE_NAME}.account" || true
109+snap ack "${SNAP_FILE_NAME}.snap-declaration" || true
110+snap ack "${SNAP_FILE_NAME}.snap-revision" || true
111+
112+# Delete the assertions files after importing them
113+rm -f "${SNAP_FILE_NAME}.*"
114+
115+snap install ${SNAP_FILE_NAME}
116
117=== modified file 'debian/control'
118--- debian/control 2016-09-21 14:55:05 +0000
119+++ debian/control 2016-09-21 14:55:05 +0000
120@@ -40,16 +40,19 @@
121 Package: unity-scope-click
122 Architecture: armhf arm64 i386 amd64
123 Depends: account-plugin-ubuntuone,
124+ grep,
125+ libdigest-sha3-perl,
126 libglib2.0-bin,
127 libsqlite3-0 (>= 3.8.5),
128- packagekit,
129- packagekit-tools,
130+ snapd | packagekit,
131+ snapd | packagekit-tools,
132 pay-service,
133 ubuntu-app-launch-tools,
134 ubuntu-download-manager,
135- ubuntu-sdk-libs,
136+ snapd | ubuntu-sdk-libs,
137 unity-scope-click-departmentsdb (= ${binary:Version}),
138 upstart,
139+ wget,
140 ${misc:Depends},
141 ${shlibs:Depends},
142 Breaks: unity (<< 7.0),
143
144=== modified file 'libclickscope/click/configuration.cpp'
145--- libclickscope/click/configuration.cpp 2016-02-19 03:35:43 +0000
146+++ libclickscope/click/configuration.cpp 2016-09-21 14:55:05 +0000
147@@ -1,5 +1,5 @@
148 /*
149- * Copyright (C) 2014-2015 Canonical Ltd.
150+ * Copyright (C) 2014-2016 Canonical Ltd.
151 *
152 * This program is free software: you can redistribute it and/or modify it
153 * under the terms of the GNU General Public License version 3, as published
154@@ -27,6 +27,8 @@
155 * files in the program, then also delete it here.
156 */
157
158+#include "configuration.h"
159+
160 #include <string>
161 #include <vector>
162
163@@ -43,8 +45,9 @@
164
165 #include <boost/algorithm/string.hpp>
166 #include <boost/algorithm/string/replace.hpp>
167-
168-#include "configuration.h"
169+#include <sys/stat.h>
170+#include <sys/types.h>
171+#include <unistd.h>
172
173 namespace click {
174
175@@ -121,6 +124,13 @@
176 return arch;
177 }
178
179+bool Configuration::is_snapd_running() const
180+{
181+ struct stat sb;
182+ int retval = stat("/run/snapd.socket", &sb);
183+ return retval == 0 && (sb.st_mode & S_IFMT) == S_IFSOCK;
184+}
185+
186 bool Configuration::get_purchases_enabled()
187 {
188 const char* env_value = std::getenv(PURCHASES_ENVVAR);
189
190=== modified file 'libclickscope/click/configuration.h'
191--- libclickscope/click/configuration.h 2016-09-21 14:55:05 +0000
192+++ libclickscope/click/configuration.h 2016-09-21 14:55:05 +0000
193@@ -54,6 +54,7 @@
194
195 virtual std::vector<std::string> get_available_frameworks();
196 virtual std::string get_architecture();
197+ virtual bool is_snapd_running() const;
198 static bool get_purchases_enabled();
199 static std::string get_currency(const std::string& fallback = CURRENCY_DEFAULT);
200
201
202=== modified file 'libclickscope/click/download-manager.cpp'
203--- libclickscope/click/download-manager.cpp 2016-05-10 13:42:12 +0000
204+++ libclickscope/click/download-manager.cpp 2016-09-21 14:55:05 +0000
205@@ -57,12 +57,6 @@
206
207 static const QString DOWNLOAD_MANAGER_SHA512 = "sha512";
208
209-const QByteArray& CLICK_TOKEN_HEADER()
210-{
211- static const QByteArray result("X-Click-Token");
212- return result;
213-}
214-
215 DownloadManager::DownloadManager(const QSharedPointer<click::web::Client>& client,
216 const QSharedPointer<udm::Manager>& manager) :
217 client(client),
218@@ -86,11 +80,8 @@
219 if (downloads.size() > 0) {
220 auto download = downloads.at(0);
221 object_path = download->id().toStdString();
222- }
223- qDebug() << "Found object path" << QString::fromStdString(object_path)
224- << "for package" << QString::fromStdString(package_name);
225- if (downloads.size() > 1) {
226- qWarning() << "More than one download with the same object path";
227+ qDebug() << "Found object path" << QString::fromStdString(object_path)
228+ << "for package" << QString::fromStdString(package_name);
229 }
230 callback(object_path);
231 }, [callback, package_name](const QString& /*key*/, const QString& /*value*/, DownloadsList* /*downloads_list*/){
232@@ -100,78 +91,57 @@
233 });
234 }
235
236-click::web::Cancellable DownloadManager::start(const std::string& url,
237- const std::string& download_sha512,
238- const std::string& package_name,
239- const std::function<void (std::string, Error)>& callback)
240-{
241- QSharedPointer<click::web::Response> response = client->call
242- (url, "HEAD", true);
243-
244- QObject::connect(response.data(), &click::web::Response::finished,
245- [this, callback, url, download_sha512, package_name,
246- response](QString) {
247- auto status = response->get_status_code();
248- if (status == 200) {
249- auto clickToken = response->get_header(CLICK_TOKEN_HEADER().data());
250- qDebug() << "Received click token:" << clickToken.c_str();
251- QVariantMap metadata;
252-
253- QVariant commandline = QVariant(QStringList() << DOWNLOAD_COMMAND << "$file" << package_name.c_str());
254- metadata[DOWNLOAD_COMMAND_KEY] = commandline;
255- metadata[DOWNLOAD_APP_ID_KEY] = package_name.c_str();
256- metadata["package_name"] = package_name.c_str();
257-
258- QMap<QString, QString> headers;
259- headers[CLICK_TOKEN_HEADER()] = clickToken.c_str();
260-
261- udm::DownloadStruct downloadStruct(url.c_str(),
262- download_sha512.c_str(),
263- DOWNLOAD_MANAGER_SHA512,
264- metadata,
265- headers);
266-
267- dm->createDownload(downloadStruct,
268- [callback](Download* download) {
269- if (download->isError()) {
270- auto error = download->error()->errorString().toUtf8().data();
271- qDebug() << "Received error from ubuntu-download-manager:" << error;
272- callback(error, Error::DownloadInstallError);
273- } else {
274- download->start();
275- callback(download->id().toUtf8().data(), Error::NoError);
276- }
277- },
278- [callback](Download* download) {
279- callback(download->error()->errorString().toUtf8().data(),
280- Error::DownloadInstallError);
281- });
282- } else {
283- std::string error{"Unhandled HTTP response code: "};
284- error += status;
285- callback(error, Error::DownloadInstallError);
286- }
287- });
288- QObject::connect(response.data(), &click::web::Response::error,
289- [this, callback, package_name](QString error, int error_code) {
290- qWarning() << QStringLiteral("Network error (%1) fetching click token for:").arg(error_code) << package_name.c_str();
291- switch(error_code) {
292- case 401:
293- case 403:
294- client->invalidateCredentials();
295- callback(error.toUtf8().data(), Error::CredentialsError);
296- break;
297- default:
298- callback(error.toUtf8().data(), Error::DownloadInstallError);
299- }
300- });
301-
302- return click::web::Cancellable(response);
303-}
304-
305-void DownloadManager::setCredentialsService(const QSharedPointer<click::CredentialsService>& credentialsService)
306-{
307- sso = credentialsService;
308+void DownloadManager::start(const std::string& url,
309+ const std::string& download_sha512,
310+ const std::string& package_name,
311+ const std::function<void (std::string, Error)>& callback)
312+{
313+ auto signature = client->signUrl(url, "GET");
314+
315+ QVariantMap metadata;
316+
317+ auto commandline = QVariant(QStringList() << DOWNLOAD_COMMAND << "$file" << package_name.c_str());
318+ metadata[DOWNLOAD_COMMAND_KEY] = commandline;
319+ metadata[DOWNLOAD_APP_ID_KEY] = package_name.c_str();
320+ metadata["package_name"] = package_name.c_str();
321+
322+ QMap<QString, QString> headers;
323+ headers[click::web::AUTHORIZATION_HEADER.c_str()] = signature.c_str();
324+
325+ udm::DownloadStruct downloadStruct(url.c_str(),
326+ download_sha512.c_str(),
327+ DOWNLOAD_MANAGER_SHA512,
328+ metadata,
329+ headers);
330+
331+ dm->createDownload(downloadStruct,
332+ [callback](Download* download) {
333+ if (download != nullptr) {
334+ if (download->isError()) {
335+ auto errorstr = download->error()->errorString();
336+ auto error = errorstr.toStdString();
337+ qDebug() << "Received error from ubuntu-download-manager:" << errorstr;
338+ callback(error, Error::DownloadInstallError);
339+ } else {
340+ download->start();
341+ callback(download->id().toStdString(),
342+ Error::NoError);
343+ }
344+ } else {
345+ callback("Received nullptr for download.",
346+ Error::DownloadInstallError);
347+ }
348+ },
349+ [callback](Download* download) {
350+ if (download != nullptr) {
351+ auto errorstr = download->error()->errorString();
352+ auto error = errorstr.toStdString();
353+ callback(error, Error::DownloadInstallError);
354+ } else {
355+ callback("Received nullptr for download.",
356+ Error::DownloadInstallError);
357+ }
358+ });
359 }
360
361 } // namespace click
362
363=== modified file 'libclickscope/click/download-manager.h'
364--- libclickscope/click/download-manager.h 2016-02-26 18:51:22 +0000
365+++ libclickscope/click/download-manager.h 2016-09-21 14:55:05 +0000
366@@ -68,18 +68,14 @@
367
368 virtual void get_progress(const std::string& package_name,
369 const std::function<void (std::string)>& callback);
370- virtual click::web::Cancellable start(const std::string& url,
371- const std::string& download_sha512,
372- const std::string& package_name,
373- const std::function<void (std::string,
374- Error)>& callback);
375-
376- virtual void setCredentialsService(const QSharedPointer<click::CredentialsService>& credentialsService);
377+ virtual void start(const std::string& url,
378+ const std::string& download_sha512,
379+ const std::string& package_name,
380+ const std::function<void (std::string, Error)>& callback);
381
382 protected:
383 QSharedPointer<click::web::Client> client;
384 QSharedPointer<Ubuntu::DownloadManager::Manager> dm;
385- QSharedPointer<click::CredentialsService> sso;
386 };
387
388 }
389
390=== modified file 'libclickscope/click/index.cpp'
391--- libclickscope/click/index.cpp 2016-04-26 10:56:47 +0000
392+++ libclickscope/click/index.cpp 2016-09-21 14:55:05 +0000
393@@ -112,8 +112,13 @@
394 std::map<std::string, std::string> Index::build_headers()
395 {
396 std::stringstream frameworks;
397- for (auto f: configuration->get_available_frameworks()) {
398- frameworks << "," << f;
399+ const auto frameworklist = configuration->get_available_frameworks();
400+ if (frameworklist.empty()) {
401+ frameworks << "none";
402+ } else {
403+ for (const auto& f: frameworklist) {
404+ frameworks << "," << f;
405+ }
406 }
407
408 return std::map<std::string, std::string> {
409@@ -123,6 +128,15 @@
410 };
411 }
412
413+std::map<std::string, std::string> Index::add_snap_headers(const std::map<std::string, std::string>& headers) const
414+{
415+ std::map<std::string, std::string> new_headers{headers};
416+ new_headers["X-Ubuntu-Series"] = "16"; // Need to get from snapd
417+ new_headers["X-Ubuntu-Slots"] = "unity8"; // Only want unity8-using snaps
418+
419+ return new_headers;
420+}
421+
422 std::pair<Packages, Packages> Index::package_lists_from_json(const std::string& json)
423 {
424 Json::Reader reader;
425@@ -147,6 +161,35 @@
426 return std::pair<Packages, Packages>(pl, recommends);
427 }
428
429+click::web::Cancellable Index::search_snaps(const std::string& query,
430+ std::function<void(click::Packages search_results, click::Packages recommendations)> callback,
431+ bool force_cache)
432+{
433+ click::web::CallParams params;
434+ auto built_query = build_index_query(query, "" /* No dept for snaps */);
435+ params.add(click::QUERY_ARGNAME, built_query.c_str());
436+
437+ auto headers = add_snap_headers(build_headers());
438+
439+ QSharedPointer<click::web::Response> response
440+ (client->call(get_base_url() + click::SNAP_SEARCH_PATH,
441+ "GET", true, headers, "", params, force_cache));
442+
443+ QObject::connect(response.data(), &click::web::Response::finished, [=](QString reply) {
444+ auto package_lists = package_lists_from_json(reply.toUtf8().constData());
445+ callback(package_lists.first, package_lists.second);
446+ });
447+ QObject::connect(response.data(), &click::web::Response::error, [=](QString description) {
448+ qWarning() << "No packages found due to network error:" << description;
449+ click::Packages pl;
450+ click::Packages recommends;
451+ qDebug() << "calling callback";
452+ callback(pl, recommends);
453+ qDebug() << " ...Done!";
454+ });
455+ return click::web::Cancellable(response);
456+}
457+
458 click::web::Cancellable Index::search (const std::string& query, const std::string& department,
459 std::function<void(click::Packages search_results, click::Packages recommendations)> callback,
460 bool force_cache)
461@@ -162,8 +205,8 @@
462 package_lists = package_lists_from_json(reply.toUtf8().constData());
463 callback(package_lists.first, package_lists.second);
464 });
465- QObject::connect(response.data(), &click::web::Response::error, [=](QString /*description*/) {
466- qDebug() << "No packages found due to network error";
467+ QObject::connect(response.data(), &click::web::Response::error, [=](QString description) {
468+ qWarning() << "No packages found due to network error:" << description;
469 click::Packages pl;
470 click::Packages recommends;
471 qDebug() << "calling callback";
472@@ -215,10 +258,21 @@
473 return click::web::Cancellable(response);
474 }
475
476-click::web::Cancellable Index::get_details (const std::string& package_name, std::function<void(PackageDetails, click::Index::Error)> callback, bool force_cache)
477+click::web::Cancellable Index::get_details (const std::string& package_name,
478+ std::function<void(PackageDetails,
479+ click::Index::Error)> callback,
480+ bool is_snap,
481+ bool force_cache)
482 {
483+ std::string details_path{click::DETAILS_PATH};
484+ auto headers = build_headers();
485+ if (is_snap) {
486+ details_path = click::SNAP_DETAILS_PATH;
487+ headers = add_snap_headers(headers);
488+ }
489 QSharedPointer<click::web::Response> response = client->call
490- (get_base_url() + click::DETAILS_PATH + package_name,
491+ (get_base_url() + details_path + package_name,
492+ "GET", true, headers, "",
493 click::web::CallParams(),
494 force_cache);
495 qDebug() << "getting details for" << package_name.c_str();
496
497=== modified file 'libclickscope/click/index.h'
498--- libclickscope/click/index.h 2016-04-26 10:56:47 +0000
499+++ libclickscope/click/index.h 2016-09-21 14:55:05 +0000
500@@ -1,5 +1,5 @@
501 /*
502- * Copyright (C) 2014 Canonical Ltd.
503+ * Copyright (C) 2014-2016 Canonical Ltd.
504 *
505 * This program is free software: you can redistribute it and/or modify it
506 * under the terms of the GNU General Public License version 3, as published
507@@ -49,11 +49,13 @@
508 const std::string SEARCH_BASE_URL_ENVVAR = "U1_SEARCH_BASE_URL";
509 const std::string SEARCH_BASE_URL = "https://search.apps.ubuntu.com/";
510 const std::string SEARCH_PATH = "api/v1/search";
511+const std::string SNAP_SEARCH_PATH = "api/v1/snaps/search";
512 const std::string BOOTSTRAP_PATH = "api/v1";
513 const std::string SUPPORTED_FRAMEWORKS = "framework:ubuntu-sdk-13.10";
514 const std::string QUERY_ARGNAME = "q";
515 const std::string ARCHITECTURE = "architecture:";
516 const std::string DETAILS_PATH = "api/v1/package/";
517+const std::string SNAP_DETAILS_PATH = "api/v1/snaps/details/";
518 const std::string CURRENCY_HEADER = "X-Suggested-Currency";
519
520 class PackageManager
521@@ -72,6 +74,7 @@
522 std::string m_suggested_currency;
523 virtual std::string build_index_query(const std::string& query, const std::string& department);
524 virtual std::map<std::string, std::string> build_headers();
525+ virtual std::map<std::string, std::string> add_snap_headers(const std::map<std::string, std::string>& headers) const;
526
527 public:
528 enum class Error {NoError, CredentialsError, NetworkError};
529@@ -79,9 +82,15 @@
530 Index(const QSharedPointer<click::web::Client>& client,
531 const QSharedPointer<Configuration> configuration=QSharedPointer<Configuration>(new Configuration()));
532 virtual std::pair<Packages, Packages> package_lists_from_json(const std::string& json);
533+ virtual click::web::Cancellable search_snaps(const std::string& query,
534+ std::function<void(click::Packages search_results, click::Packages recommendations)> callback,
535+ bool force_cache = false);
536 virtual click::web::Cancellable search (const std::string& query, const std::string& department, std::function<void(Packages, Packages)> callback, bool
537 force_cache = false);
538- virtual click::web::Cancellable get_details(const std::string& package_name, std::function<void(PackageDetails, Error)> callback, bool force_cache = false);
539+ virtual click::web::Cancellable get_details(const std::string& package_name,
540+ std::function<void(PackageDetails, Error)> callback,
541+ bool is_snap = false,
542+ bool force_cache = false);
543 virtual click::web::Cancellable bootstrap(std::function<void(const DepartmentList&, const HighlightList&, Error, int)> callback, bool force_cache = false);
544 virtual click::web::Cancellable departments(const std::string& department_href, std::function<void(const DepartmentList&, const HighlightList&, Error, int)>
545 callback, bool force_cache = false);
546
547=== modified file 'libclickscope/click/package.cpp'
548--- libclickscope/click/package.cpp 2015-11-24 18:23:23 +0000
549+++ libclickscope/click/package.cpp 2016-09-21 14:55:05 +0000
550@@ -95,6 +95,10 @@
551 p.publisher = item[Package::JsonKeys::publisher].asString();
552 p.rating = item[Package::JsonKeys::rating].asDouble();
553 p.version = item[Package::JsonKeys::version].asString();
554+
555+ p.snap_id = item[Package::JsonKeys::snap_id].asString();
556+ p.alias = item[Package::JsonKeys::alias].asString();
557+
558 return p;
559 }
560
561
562=== modified file 'libclickscope/click/package.h'
563--- libclickscope/click/package.h 2015-11-24 18:23:23 +0000
564+++ libclickscope/click/package.h 2016-09-21 14:55:05 +0000
565@@ -64,6 +64,8 @@
566 constexpr static const char* publisher{"publisher"};
567 constexpr static const char* rating{"ratings_average"};
568 constexpr static const char* version{"version"};
569+ constexpr static const char* snap_id{"snap_id"};
570+ constexpr static const char* alias{"alias"};
571
572 // NOTE: The "price" field is deprecated in favor of "prices"
573 constexpr static const char* prices{"prices"};
574@@ -107,6 +109,8 @@
575 void matches (std::string query, std::function<bool> callback);
576 std::string content;
577 std::map<std::string, double> prices;
578+ std::string snap_id;
579+ std::string alias;
580
581 struct hash_name {
582 public :
583
584=== modified file 'libclickscope/click/preview.cpp'
585--- libclickscope/click/preview.cpp 2016-09-21 14:55:05 +0000
586+++ libclickscope/click/preview.cpp 2016-09-21 14:55:05 +0000
587@@ -442,7 +442,11 @@
588 // and code using it does not need to worry about threading/event loop topics.
589 run_under_qt([this, details_callback, reviews_callback, app_name, force_cache]()
590 {
591- index_operation = index->get_details(app_name, [this, app_name, details_callback, reviews_callback, force_cache](PackageDetails details, click::Index::Error error){
592+ index_operation = index->get_details(app_name,
593+ [this, app_name,
594+ details_callback,
595+ reviews_callback,
596+ force_cache](PackageDetails details, click::Index::Error error){
597 if(error == click::Index::Error::NoError) {
598 qDebug() << "Got details:" << app_name.c_str();
599 details_callback(details);
600@@ -455,10 +459,17 @@
601 details.main_screenshot_url = get_string_maybe_null(result["main_screenshot"]);
602 details_callback(details);
603 }
604- reviews_operation = reviews->fetch_reviews(app_name,
605- reviews_callback,
606- force_cache);
607- }, force_cache);
608+ // FIXME: No RNR support for v2 snaps yet, so avoid the
609+ // network hit if we're showing a snap preview
610+ if (app_name.rfind(".") != std::string::npos) {
611+ reviews_operation = reviews->fetch_reviews(app_name,
612+ reviews_callback,
613+ force_cache);
614+ } else {
615+ reviews_callback(click::ReviewList{},
616+ click::Reviews::Error::NoError);
617+ }
618+ }, app_name.rfind(".") == std::string::npos, force_cache);
619 });
620 }
621 }
622
623=== modified file 'libclickscope/click/webclient.cpp'
624--- libclickscope/click/webclient.cpp 2016-05-25 16:19:51 +0000
625+++ libclickscope/click/webclient.cpp 2016-09-21 14:55:05 +0000
626@@ -78,6 +78,26 @@
627 {
628 }
629
630+std::string click::web::Client::signUrl(const std::string& url,
631+ const std::string& method)
632+{
633+ QString signature;
634+
635+ if (impl->sso.isNull()) {
636+ qCritical() << "Unable to sign request without SSO object.";
637+ } else {
638+ auto token = impl->sso->getToken();
639+ if (token.isValid()) {
640+ signature = token.signUrl(QString::fromStdString(url),
641+ QString::fromStdString(method));
642+ qDebug() << "Signed URL:" << QString::fromStdString(url);
643+ } else {
644+ qWarning() << "Signing requested but returned token is invalid.";
645+ }
646+ }
647+ return signature.toStdString();
648+}
649+
650 QSharedPointer<click::web::Response> click::web::Client::call(
651 const std::string& iri,
652 const click::web::CallParams& params,
653@@ -137,25 +157,14 @@
654 auto deviceId = Configuration().get_device_id();
655 request->setRawHeader(DEVICE_ID_HEADER.c_str(), deviceId.data());
656
657- if (sign && !impl->sso.isNull()) {
658- auto token = impl->sso->getToken();
659- if (token.isValid()) {
660- QString auth_header = token.signUrl(url.toString(),
661- method.c_str());
662- qDebug() << "Signed URL:" << request->url().toString();
663- request->setRawHeader(AUTHORIZATION_HEADER.c_str(), auth_header.toUtf8());
664- } else {
665- qWarning() << "Signing reuested but returned token is invalid.";
666- }
667-
668- doConnect();
669- } else {
670- if (sign && impl->sso.isNull()) {
671- qCritical() << "Unable to sign request without SSO object.";
672- }
673- doConnect();
674+ if (sign) {
675+ auto auth_header = signUrl(url.toString().toStdString(), method);
676+ if (!auth_header.empty())
677+ request->setRawHeader(AUTHORIZATION_HEADER.c_str(),
678+ auth_header.c_str());
679 }
680
681+ doConnect();
682
683 return responsePtr;
684 }
685
686=== modified file 'libclickscope/click/webclient.h'
687--- libclickscope/click/webclient.h 2016-05-25 16:19:51 +0000
688+++ libclickscope/click/webclient.h 2016-09-21 14:55:05 +0000
689@@ -115,6 +115,8 @@
690 Client(const QSharedPointer<click::network::AccessManager>& networkAccessManager);
691 virtual ~Client();
692
693+ virtual std::string signUrl(const std::string& url,
694+ const std::string& method);
695 virtual QSharedPointer<Response> call(
696 const std::string& iri,
697 const CallParams& params = CallParams(), bool force_cache = false);
698
699=== modified file 'libclickscope/tests/mock_webclient.h'
700--- libclickscope/tests/mock_webclient.h 2016-05-25 16:19:51 +0000
701+++ libclickscope/tests/mock_webclient.h 2016-09-21 14:55:05 +0000
702@@ -61,13 +61,6 @@
703 Mock instance;
704 };
705
706-QSharedPointer<click::web::Response> responseForReply(const QSharedPointer<click::network::Reply>& reply)
707-{
708- auto response = QSharedPointer<click::web::Response>(new click::web::Response(QSharedPointer<QNetworkRequest>(new QNetworkRequest()), QSharedPointer<QBuffer>(new QBuffer())));
709- response->setReply(reply);
710- return response;
711-}
712-
713 class MockClient : public click::web::Client
714 {
715 public:
716@@ -76,6 +69,7 @@
717 {
718 }
719
720+ MOCK_METHOD2(signUrl, std::string(const std::string&, const std::string&));
721 // Mocking default arguments: https://groups.google.com/forum/#!topic/googlemock/XrabW20vV7o
722 MOCK_METHOD6(callImpl, QSharedPointer<click::web::Response>(
723 const std::string& iri,
724@@ -102,6 +96,16 @@
725
726 MOCK_METHOD1(has_header, bool(const std::string& header));
727 MOCK_METHOD1(get_header, std::string(const std::string&header));
728+
729+ static QSharedPointer<click::web::Response> responseForReply(const QSharedPointer<click::network::Reply>& reply)
730+ {
731+ auto response = QSharedPointer<click::web::Response>
732+ (new click::web::Response(QSharedPointer<QNetworkRequest>(new QNetworkRequest()),
733+ QSharedPointer<QBuffer>(new QBuffer())));
734+ response->setReply(reply);
735+ return response;
736+ }
737+
738 };
739
740 }
741
742=== modified file 'libclickscope/tests/test_bootstrap.cpp'
743--- libclickscope/tests/test_bootstrap.cpp 2016-06-30 20:42:56 +0000
744+++ libclickscope/tests/test_bootstrap.cpp 2016-09-21 14:55:05 +0000
745@@ -70,7 +70,7 @@
746 TEST_F(BootstrapTest, testBootstrapCallsWebservice)
747 {
748 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
749- auto response = responseForReply(reply.asSharedPtr());
750+ auto response = MockClient::responseForReply(reply.asSharedPtr());
751
752 EXPECT_CALL(*clientPtr, callImpl(EndsWith(click::BOOTSTRAP_PATH), "GET", _, _, _, _))
753 .Times(1)
754@@ -81,7 +81,7 @@
755 TEST_F(BootstrapTest, testBootstrapJsonIsParsed)
756 {
757 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
758- auto response = responseForReply(reply.asSharedPtr());
759+ auto response = MockClient::responseForReply(reply.asSharedPtr());
760
761 QByteArray fake_json(FAKE_JSON_BOOTSTRAP.c_str());
762 EXPECT_CALL(reply.instance, readAll())
763
764=== modified file 'libclickscope/tests/test_download_manager.cpp'
765--- libclickscope/tests/test_download_manager.cpp 2016-05-10 13:42:12 +0000
766+++ libclickscope/tests/test_download_manager.cpp 2016-09-21 14:55:05 +0000
767@@ -63,6 +63,7 @@
768
769 virtual void SetUp()
770 {
771+ sdmPtr.reset(new MockSystemDownloadManager());
772 ssoPtr.reset(new MockCredentialsService());
773 namPtr.reset(new MockNetworkAccessManager());
774 clientPtr.reset(new NiceMock<MockClient>(namPtr));
775@@ -76,138 +77,165 @@
776
777 }
778
779-TEST_F(DownloadManagerTest, testStartCallsWebservice)
780+TEST_F(DownloadManagerTest, testStartCallsSignUrl)
781 {
782- LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
783- auto response = responseForReply(reply.asSharedPtr());
784-
785- EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
786- .Times(1)
787- .WillOnce(Return(response));
788-
789+ EXPECT_CALL(*clientPtr, signUrl(_, "GET")).Times(1);
790+ EXPECT_CALL(*sdmPtr, createDownload(_, _, _)).Times(1);
791 dmPtr->start("", "", "",
792 [](std::string, click::DownloadManager::Error) {});
793 }
794
795-TEST_F(DownloadManagerTest, testStartCallbackCalled)
796-{
797- LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
798- auto response = responseForReply(reply.asSharedPtr());
799-
800- EXPECT_CALL(reply.instance, attribute(_)).WillOnce(Return(QVariant(0)));
801- EXPECT_CALL(reply.instance, readAll())
802- .Times(1)
803- .WillOnce(Return(""));
804- EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
805- .Times(1)
806- .WillOnce(Return(response));
807- EXPECT_CALL(*this, start_callback(_, _)).Times(1);
808-
809- dmPtr->start("", "", "",
810- [this](std::string msg, click::DownloadManager::Error err) {
811- start_callback(msg, err);
812- });
813- response->replyFinished();
814-}
815-
816-TEST_F(DownloadManagerTest, testStartHTTPForbidden)
817-{
818- LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
819- auto response = responseForReply(reply.asSharedPtr());
820-
821- EXPECT_CALL(reply.instance, attribute(_)).WillOnce(Return(QVariant(403)));
822- EXPECT_CALL(reply.instance, readAll())
823- .Times(1)
824- .WillOnce(Return(""));
825- EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
826- .Times(1)
827- .WillOnce(Return(response));
828- EXPECT_CALL(*this, start_callback(StartsWith("Unhandled HTTP response code:"),
829- click::DownloadManager::Error::DownloadInstallError)).Times(1);
830-
831- dmPtr->start("", "", "",
832- [this](std::string msg, click::DownloadManager::Error err) {
833- start_callback(msg, err);
834- });
835- response->replyFinished();
836-}
837-
838-TEST_F(DownloadManagerTest, testStartHTTPError)
839-{
840- LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
841- auto response = responseForReply(reply.asSharedPtr());
842-
843- EXPECT_CALL(reply.instance, errorString())
844- .WillOnce(Return(QString("ERROR")));
845- EXPECT_CALL(reply.instance, attribute(_)).WillOnce(Return(QVariant(404)));
846- EXPECT_CALL(reply.instance, readAll())
847- .Times(1)
848- .WillOnce(Return(""));
849- EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
850- .Times(1)
851- .WillOnce(Return(response));
852- EXPECT_CALL(*this, start_callback("ERROR (203)",
853- click::DownloadManager::Error::DownloadInstallError)).Times(1);
854-
855- dmPtr->start("", "", "",
856- [this](std::string msg, click::DownloadManager::Error err) {
857- start_callback(msg, err);
858- });
859- response->errorHandler(QNetworkReply::ContentNotFoundError);
860-}
861-
862-TEST_F(DownloadManagerTest, testStartCredentialsError)
863-{
864- LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
865- auto response = responseForReply(reply.asSharedPtr());
866-
867- EXPECT_CALL(reply.instance, errorString())
868- .WillOnce(Return(QString("ERROR")));
869- EXPECT_CALL(reply.instance, attribute(_)).WillOnce(Return(QVariant(401)));
870- EXPECT_CALL(reply.instance, readAll())
871- .Times(1)
872- .WillOnce(Return(""));
873- EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
874- .Times(1)
875- .WillOnce(Return(response));
876- EXPECT_CALL(*ssoPtr, invalidateCredentials());
877- EXPECT_CALL(*this, start_callback("ERROR (201)",
878- click::DownloadManager::Error::CredentialsError)).Times(1);
879-
880- dmPtr->start("", "", "test.package",
881- [this](std::string msg, click::DownloadManager::Error err) {
882- start_callback(msg, err);
883- });
884- response->errorHandler(QNetworkReply::ContentAccessDenied);
885-}
886-
887-// FIXME: createDownload() SEGV under tests
888-TEST_F(DownloadManagerTest, DISABLED_testStartDownloadCreated)
889-{
890- LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
891- auto response = responseForReply(reply.asSharedPtr());
892-
893- EXPECT_CALL(reply.instance, rawHeader(QByteArray("X-Click-Token")))
894- .Times(1)
895- .WillOnce(Return(QString("clicktoken")));
896- EXPECT_CALL(reply.instance, attribute(_)).WillOnce(Return(QVariant(200)));
897- EXPECT_CALL(reply.instance, readAll())
898- .Times(1)
899- .WillOnce(Return(""));
900- EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
901- .Times(1)
902- .WillOnce(Return(response));
903-
904- EXPECT_CALL(*sdmPtr, createDownload(_, _, _));
905- dmPtr->start("", "", "test.package",
906- [this](std::string msg, click::DownloadManager::Error err) {
907- start_callback(msg, err);
908- });
909- response->replyFinished();
910-}
911-
912-// FIXME: getAllDownloadsWithMetadata() SEGV under tests
913-TEST_F(DownloadManagerTest, DISABLED_testGetProgressNoDownloads)
914+TEST_F(DownloadManagerTest, testStartDownloadSuccssIsError)
915+{
916+ auto mockDownload = new MockDownload();
917+ auto mockError = new MockError();
918+ EXPECT_CALL(*mockDownload, isError())
919+ .Times(1)
920+ .WillOnce(Return(true));
921+ EXPECT_CALL(*mockDownload, error())
922+ .Times(1)
923+ .WillOnce(Return(mockError));
924+ EXPECT_CALL(*mockError, errorString())
925+ .Times(1)
926+ .WillOnce(Return(QStringLiteral("")));
927+
928+ EXPECT_CALL(*clientPtr, signUrl(_, "GET")).Times(1);
929+ EXPECT_CALL(*sdmPtr, createDownload(_, _, _))
930+ .Times(1)
931+ .WillOnce(InvokeArgument<1>(mockDownload));
932+ EXPECT_CALL(*this, start_callback(_, _)).Times(1);
933+
934+ dmPtr->start("", "", "",
935+ [this](std::string msg, click::DownloadManager::Error err) {
936+ start_callback(msg, err);
937+ });
938+
939+ delete mockError;
940+ delete mockDownload;
941+}
942+
943+TEST_F(DownloadManagerTest, testStartDownloadSuccssCallsStart)
944+{
945+ auto mockDownload = new MockDownload();
946+ EXPECT_CALL(*mockDownload, isError())
947+ .Times(1)
948+ .WillOnce(Return(false));
949+ EXPECT_CALL(*mockDownload, start()).Times(1);
950+ EXPECT_CALL(*mockDownload, id())
951+ .Times(1)
952+ .WillOnce(Return(QStringLiteral("download")));
953+
954+ EXPECT_CALL(*clientPtr, signUrl(_, "GET")).Times(1);
955+ EXPECT_CALL(*sdmPtr, createDownload(_, _, _))
956+ .Times(1)
957+ .WillOnce(InvokeArgument<1>(mockDownload));
958+ EXPECT_CALL(*this, start_callback(_, _)).Times(1);
959+
960+ dmPtr->start("", "", "",
961+ [this](std::string msg, click::DownloadManager::Error err) {
962+ start_callback(msg, err);
963+ });
964+
965+ delete mockDownload;
966+}
967+
968+TEST_F(DownloadManagerTest, testStartErrorCallback)
969+{
970+ auto mockDownload = new MockDownload();
971+ auto mockError = new MockError();
972+ EXPECT_CALL(*mockDownload, error())
973+ .Times(1)
974+ .WillOnce(Return(mockError));
975+ EXPECT_CALL(*mockError, errorString())
976+ .Times(1)
977+ .WillOnce(Return(QStringLiteral("")));
978+
979+ EXPECT_CALL(*clientPtr, signUrl(_, "GET")).Times(1);
980+ EXPECT_CALL(*sdmPtr, createDownload(_, _, _))
981+ .Times(1)
982+ .WillOnce(InvokeArgument<2>(mockDownload));
983+ EXPECT_CALL(*this, start_callback(_, _)).Times(1);
984+
985+ dmPtr->start("", "", "",
986+ [this](std::string msg, click::DownloadManager::Error err) {
987+ start_callback(msg, err);
988+ });
989+
990+ delete mockError;
991+ delete mockDownload;
992+}
993+
994+TEST_F(DownloadManagerTest, testGetProgressDownloadFound)
995+{
996+ auto mockDownloadsList = new MockDownloadsList();
997+ auto mockDownload = QSharedPointer<MockDownload>(new MockDownload());
998+
999+ QList<QSharedPointer<Ubuntu::DownloadManager::Download>> downloads{mockDownload};
1000+
1001+ EXPECT_CALL(*mockDownload, id())
1002+ .Times(1)
1003+ .WillOnce(Return("download"));
1004+ EXPECT_CALL(*mockDownloadsList, downloads())
1005+ .Times(1)
1006+ .WillOnce(Return(downloads));
1007+ EXPECT_CALL(*sdmPtr, getAllDownloadsWithMetadata(_, _, _, _))
1008+ .Times(1)
1009+ .WillOnce(InvokeArgument<2>(QStringLiteral(""), QStringLiteral(""),
1010+ mockDownloadsList));
1011+ dmPtr->get_progress("com.example.test",
1012+ [this](std::string object_path) {
1013+ progress_callback(object_path);
1014+ });
1015+
1016+ delete mockDownloadsList;
1017+}
1018+
1019+TEST_F(DownloadManagerTest, testGetProgressMultipleDownloadsFound)
1020+{
1021+ auto mockDownloadsList = new MockDownloadsList();
1022+ auto mockDownload = QSharedPointer<MockDownload>(new MockDownload());
1023+ auto mockDownload2 = QSharedPointer<MockDownload>(new MockDownload());
1024+
1025+ QList<QSharedPointer<Ubuntu::DownloadManager::Download>> downloads{mockDownload, mockDownload2};
1026+
1027+ EXPECT_CALL(*mockDownload, id())
1028+ .Times(1)
1029+ .WillOnce(Return("download"));
1030+ EXPECT_CALL(*mockDownloadsList, downloads())
1031+ .Times(1)
1032+ .WillOnce(Return(downloads));
1033+ EXPECT_CALL(*sdmPtr, getAllDownloadsWithMetadata(_, _, _, _))
1034+ .Times(1)
1035+ .WillOnce(InvokeArgument<2>(QStringLiteral(""), QStringLiteral(""),
1036+ mockDownloadsList));
1037+ dmPtr->get_progress("com.example.test",
1038+ [this](std::string object_path) {
1039+ progress_callback(object_path);
1040+ });
1041+
1042+ delete mockDownloadsList;
1043+}
1044+
1045+TEST_F(DownloadManagerTest, testGetProgressNoDownloadsFound)
1046+{
1047+ auto mockDownloadsList = new MockDownloadsList();
1048+ QList<QSharedPointer<Ubuntu::DownloadManager::Download>> emptyDownloads{};
1049+ EXPECT_CALL(*mockDownloadsList, downloads())
1050+ .Times(1)
1051+ .WillOnce(Return(emptyDownloads));
1052+ EXPECT_CALL(*sdmPtr, getAllDownloadsWithMetadata(_, _, _, _))
1053+ .Times(1)
1054+ .WillOnce(InvokeArgument<2>(QStringLiteral(""), QStringLiteral(""),
1055+ mockDownloadsList));
1056+ dmPtr->get_progress("com.example.test",
1057+ [this](std::string object_path) {
1058+ progress_callback(object_path);
1059+ });
1060+
1061+ delete mockDownloadsList;
1062+}
1063+
1064+TEST_F(DownloadManagerTest, testGetProgressErrorCallback)
1065 {
1066 EXPECT_CALL(*sdmPtr, getAllDownloadsWithMetadata(_, _, _, _))
1067 .Times(1)
1068
1069=== modified file 'libclickscope/tests/test_index.cpp'
1070--- libclickscope/tests/test_index.cpp 2016-05-10 13:42:12 +0000
1071+++ libclickscope/tests/test_index.cpp 2016-09-21 14:55:05 +0000
1072@@ -66,7 +66,7 @@
1073 };
1074
1075
1076-class IndexTest : public ::testing::Test {
1077+class SimpleIndexTest : public ::testing::Test {
1078 protected:
1079 QSharedPointer<MockClient> clientPtr;
1080 QSharedPointer<MockNetworkAccessManager> namPtr;
1081@@ -86,6 +86,18 @@
1082 MOCK_METHOD2(details_callback, void(click::PackageDetails, click::Index::Error));
1083 };
1084
1085+class IndexTest : public SimpleIndexTest {
1086+ virtual void SetUp() {
1087+ SimpleIndexTest::SetUp();
1088+ EXPECT_CALL(*configPtr, get_architecture())
1089+ .Times(1)
1090+ .WillOnce(Return(fake_arch));
1091+ EXPECT_CALL(*configPtr, get_available_frameworks())
1092+ .Times(1)
1093+ .WillOnce(Return(fake_frameworks));
1094+ }
1095+};
1096+
1097 class MockPackageManager : public click::PackageManager, public ::testing::Test
1098 {
1099 public:
1100@@ -97,14 +109,8 @@
1101 TEST_F(IndexTest, testSearchCallsWebservice)
1102 {
1103 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1104- auto response = responseForReply(reply.asSharedPtr());
1105+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1106
1107- EXPECT_CALL(*configPtr, get_architecture())
1108- .Times(1)
1109- .WillOnce(Return(fake_arch));
1110- EXPECT_CALL(*configPtr, get_available_frameworks())
1111- .Times(1)
1112- .WillOnce(Return(fake_frameworks));
1113 EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
1114 .Times(1)
1115 .WillOnce(Return(response));
1116@@ -120,14 +126,8 @@
1117 TEST_F(IndexTest, testSearchQueryIsLowercase)
1118 {
1119 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1120- auto response = responseForReply(reply.asSharedPtr());
1121+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1122
1123- EXPECT_CALL(*configPtr, get_architecture())
1124- .Times(1)
1125- .WillOnce(Return(fake_arch));
1126- EXPECT_CALL(*configPtr, get_available_frameworks())
1127- .Times(1)
1128- .WillOnce(Return(fake_frameworks));
1129 EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, QueryContains("foobar")))
1130 .Times(1)
1131 .WillOnce(Return(response));
1132@@ -139,14 +139,8 @@
1133 TEST_F(IndexTest, testSearchSignsCall)
1134 {
1135 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1136- auto response = responseForReply(reply.asSharedPtr());
1137+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1138
1139- EXPECT_CALL(*configPtr, get_architecture())
1140- .Times(1)
1141- .WillOnce(Return(fake_arch));
1142- EXPECT_CALL(*configPtr, get_available_frameworks())
1143- .Times(1)
1144- .WillOnce(Return(fake_frameworks));
1145 EXPECT_CALL(*clientPtr, callImpl(_, _, true, _, _, _))
1146 .Times(1)
1147 .WillOnce(Return(response));
1148@@ -154,17 +148,119 @@
1149 indexPtr->search("", "", [](click::Packages, click::Packages) {});
1150 }
1151
1152+TEST_F(IndexTest, testSearchSnapsCallsWebservice)
1153+{
1154+ LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1155+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1156+
1157+ EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
1158+ .Times(1)
1159+ .WillOnce(Return(response));
1160+
1161+ indexPtr->search_snaps("", [](click::Packages, click::Packages) {});
1162+}
1163+
1164+TEST_F(IndexTest, testSearchSnapsSendsRightPath)
1165+{
1166+ LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1167+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1168+
1169+ EXPECT_CALL(*clientPtr, callImpl(EndsWith(click::SNAP_SEARCH_PATH),
1170+ _, _, _, _, _))
1171+ .Times(1)
1172+ .WillOnce(Return(response));
1173+
1174+ indexPtr->search_snaps("", [](click::Packages, click::Packages) {});
1175+}
1176+
1177+TEST_F(IndexTest, testSearchSnapsQueryIsLowercase)
1178+{
1179+ LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1180+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1181+
1182+ EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, QueryContains("foobar")))
1183+ .Times(1)
1184+ .WillOnce(Return(response));
1185+
1186+ indexPtr->search_snaps("FooBar", [](click::Packages, click::Packages) {});
1187+}
1188+
1189+
1190+TEST_F(IndexTest, testSearchSnapsSignsCall)
1191+{
1192+ LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1193+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1194+
1195+ EXPECT_CALL(*clientPtr, callImpl(_, _, true, _, _, _))
1196+ .Times(1)
1197+ .WillOnce(Return(response));
1198+
1199+ indexPtr->search_snaps("", [](click::Packages, click::Packages) {});
1200+}
1201+
1202+TEST_F(IndexTest, testSearchSnapsIsCancellable)
1203+{
1204+ LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1205+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1206+
1207+ EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
1208+ .Times(1)
1209+ .WillOnce(Return(response));
1210+
1211+ auto search_operation = indexPtr->search_snaps("", [](click::Packages,
1212+ click::Packages) {});
1213+ EXPECT_CALL(reply.instance, abort()).Times(1);
1214+ search_operation.cancel();
1215+}
1216+
1217+TEST_F(IndexTest, testSearchSnapsEmptyJsonIsParsed)
1218+{
1219+ LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1220+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1221+
1222+ QByteArray fake_json("[]");
1223+ EXPECT_CALL(reply.instance, readAll())
1224+ .Times(1)
1225+ .WillOnce(Return(fake_json));
1226+ EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
1227+ .Times(1)
1228+ .WillOnce(Return(response));
1229+ click::Packages empty_package_list;
1230+ EXPECT_CALL(*this, search_callback(empty_package_list, _)).Times(1);
1231+
1232+ indexPtr->search_snaps("", [this](click::Packages packages,
1233+ click::Packages recommends){
1234+ search_callback(packages, recommends);
1235+ });
1236+ response->replyFinished();
1237+}
1238+
1239+TEST_F(IndexTest, testSearchSnapsNetworkErrorIgnored)
1240+{
1241+ LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1242+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1243+
1244+ EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
1245+ .Times(1)
1246+ .WillOnce(Return(response));
1247+ EXPECT_CALL(reply.instance, errorString()).Times(1)
1248+ .WillOnce(Return("fake error"));
1249+ indexPtr->search_snaps("", [this](click::Packages packages,
1250+ click::Packages recommends){
1251+ search_callback(packages, recommends);
1252+ });
1253+
1254+ click::Packages empty_package_list;
1255+ EXPECT_CALL(*this, search_callback(empty_package_list, _)).Times(1);
1256+
1257+ emit reply.instance.error(QNetworkReply::UnknownNetworkError);
1258+}
1259+
1260 TEST_F(IndexTest, testBootstrapSignsCall)
1261 {
1262 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1263- auto response = responseForReply(reply.asSharedPtr());
1264+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1265
1266- EXPECT_CALL(*configPtr, get_architecture())
1267- .Times(1)
1268- .WillOnce(Return(fake_arch));
1269- EXPECT_CALL(*configPtr, get_available_frameworks())
1270- .Times(1)
1271- .WillOnce(Return(fake_frameworks));
1272 EXPECT_CALL(*clientPtr, callImpl(_, _, true, _, _, _))
1273 .Times(1)
1274 .WillOnce(Return(response));
1275@@ -175,14 +271,8 @@
1276 TEST_F(IndexTest, testDepartmentsSignsCall)
1277 {
1278 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1279- auto response = responseForReply(reply.asSharedPtr());
1280+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1281
1282- EXPECT_CALL(*configPtr, get_architecture())
1283- .Times(1)
1284- .WillOnce(Return(fake_arch));
1285- EXPECT_CALL(*configPtr, get_available_frameworks())
1286- .Times(1)
1287- .WillOnce(Return(fake_frameworks));
1288 EXPECT_CALL(*clientPtr, callImpl(_, _, true, _, _, _))
1289 .Times(1)
1290 .WillOnce(Return(response));
1291@@ -193,7 +283,7 @@
1292 TEST_F(IndexTest, testDetailsSignsCall)
1293 {
1294 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1295- auto response = responseForReply(reply.asSharedPtr());
1296+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1297
1298 EXPECT_CALL(*clientPtr, callImpl(_, _, true, _, _, _))
1299 .Times(1)
1300@@ -205,14 +295,8 @@
1301 TEST_F(IndexTest, testSearchSendsRightPath)
1302 {
1303 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1304- auto response = responseForReply(reply.asSharedPtr());
1305+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1306
1307- EXPECT_CALL(*configPtr, get_architecture())
1308- .Times(1)
1309- .WillOnce(Return(fake_arch));
1310- EXPECT_CALL(*configPtr, get_available_frameworks())
1311- .Times(1)
1312- .WillOnce(Return(fake_frameworks));
1313 EXPECT_CALL(*clientPtr, callImpl(EndsWith(click::SEARCH_PATH),
1314 _, _, _, _, _))
1315 .Times(1)
1316@@ -224,18 +308,12 @@
1317 TEST_F(IndexTest, testSearchCallbackIsCalled)
1318 {
1319 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1320- auto response = responseForReply(reply.asSharedPtr());
1321+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1322
1323 QByteArray fake_json("[]");
1324 EXPECT_CALL(reply.instance, readAll())
1325 .Times(1)
1326 .WillOnce(Return(fake_json));
1327- EXPECT_CALL(*configPtr, get_architecture())
1328- .Times(1)
1329- .WillOnce(Return(fake_arch));
1330- EXPECT_CALL(*configPtr, get_available_frameworks())
1331- .Times(1)
1332- .WillOnce(Return(fake_frameworks));
1333 EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
1334 .Times(1)
1335 .WillOnce(Return(response));
1336@@ -251,18 +329,12 @@
1337 TEST_F(IndexTest, testSearchEmptyJsonIsParsed)
1338 {
1339 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1340- auto response = responseForReply(reply.asSharedPtr());
1341+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1342
1343 QByteArray fake_json("[]");
1344 EXPECT_CALL(reply.instance, readAll())
1345 .Times(1)
1346 .WillOnce(Return(fake_json));
1347- EXPECT_CALL(*configPtr, get_architecture())
1348- .Times(1)
1349- .WillOnce(Return(fake_arch));
1350- EXPECT_CALL(*configPtr, get_available_frameworks())
1351- .Times(1)
1352- .WillOnce(Return(fake_frameworks));
1353 EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
1354 .Times(1)
1355 .WillOnce(Return(response));
1356@@ -279,18 +351,12 @@
1357 TEST_F(IndexTest, testSearchSingleJsonIsParsed)
1358 {
1359 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1360- auto response = responseForReply(reply.asSharedPtr());
1361+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1362
1363 QByteArray fake_json(FAKE_JSON_SEARCH_RESULT_ONE.c_str());
1364 EXPECT_CALL(reply.instance, readAll())
1365 .Times(1)
1366 .WillOnce(Return(fake_json));
1367- EXPECT_CALL(*configPtr, get_architecture())
1368- .Times(1)
1369- .WillOnce(Return(fake_arch));
1370- EXPECT_CALL(*configPtr, get_available_frameworks())
1371- .Times(1)
1372- .WillOnce(Return(fake_frameworks));
1373 EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
1374 .Times(1)
1375 .WillOnce(Return(response));
1376@@ -315,14 +381,8 @@
1377 TEST_F(IndexTest, testSearchIsCancellable)
1378 {
1379 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1380- auto response = responseForReply(reply.asSharedPtr());
1381+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1382
1383- EXPECT_CALL(*configPtr, get_architecture())
1384- .Times(1)
1385- .WillOnce(Return(fake_arch));
1386- EXPECT_CALL(*configPtr, get_available_frameworks())
1387- .Times(1)
1388- .WillOnce(Return(fake_frameworks));
1389 EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
1390 .Times(1)
1391 .WillOnce(Return(response));
1392@@ -341,14 +401,8 @@
1393 TEST_F(IndexTest, testSearchNetworkErrorIgnored)
1394 {
1395 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1396- auto response = responseForReply(reply.asSharedPtr());
1397+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1398
1399- EXPECT_CALL(*configPtr, get_architecture())
1400- .Times(1)
1401- .WillOnce(Return(fake_arch));
1402- EXPECT_CALL(*configPtr, get_available_frameworks())
1403- .Times(1)
1404- .WillOnce(Return(fake_frameworks));
1405 EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
1406 .Times(1)
1407 .WillOnce(Return(response));
1408@@ -367,7 +421,7 @@
1409 TEST_F(IndexTest, testGetDetailsCallsWebservice)
1410 {
1411 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1412- auto response = responseForReply(reply.asSharedPtr());
1413+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1414
1415 EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
1416 .Times(1)
1417@@ -379,7 +433,7 @@
1418 TEST_F(IndexTest, testGetDetailsSendsPackagename)
1419 {
1420 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1421- auto response = responseForReply(reply.asSharedPtr());
1422+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1423
1424 EXPECT_CALL(*clientPtr, callImpl(EndsWith(FAKE_PACKAGENAME),
1425 _, _, _, _, _))
1426@@ -392,7 +446,7 @@
1427 TEST_F(IndexTest, testGetDetailsSendsRightPath)
1428 {
1429 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1430- auto response = responseForReply(reply.asSharedPtr());
1431+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1432
1433 EXPECT_CALL(*clientPtr, callImpl(StartsWith(click::SEARCH_BASE_URL +
1434 click::DETAILS_PATH),
1435@@ -406,7 +460,7 @@
1436 TEST_F(IndexTest, testGetDetailsCallbackIsCalled)
1437 {
1438 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1439- auto response = responseForReply(reply.asSharedPtr());
1440+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1441
1442 QByteArray fake_json(FAKE_JSON_PACKAGE_DETAILS.c_str());
1443 EXPECT_CALL(reply.instance, readAll())
1444@@ -425,7 +479,7 @@
1445 TEST_F(IndexTest, testGetDetailsJsonIsParsed)
1446 {
1447 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1448- auto response = responseForReply(reply.asSharedPtr());
1449+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1450
1451 QByteArray fake_json(FAKE_JSON_PACKAGE_DETAILS.c_str());
1452 EXPECT_CALL(reply.instance, readAll())
1453@@ -486,7 +540,7 @@
1454 TEST_F(IndexTest, testGetDetailsJsonUtf8)
1455 {
1456 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1457- auto response = responseForReply(reply.asSharedPtr());
1458+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1459
1460 QByteArray appname_utf8("\xe5\xb0\x8f\xe6\xb5\xb7");
1461 QByteArray appname_json("\\u5c0f\\u6d77");
1462@@ -554,7 +608,7 @@
1463 TEST_F(IndexTest, testGetDetailsNetworkErrorReported)
1464 {
1465 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1466- auto response = responseForReply(reply.asSharedPtr());
1467+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1468
1469 EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
1470 .Times(1)
1471@@ -571,7 +625,7 @@
1472 TEST_F(IndexTest, testGetDetailsIsCancellable)
1473 {
1474 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1475- auto response = responseForReply(reply.asSharedPtr());
1476+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1477
1478 EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
1479 .Times(1)
1480@@ -582,7 +636,7 @@
1481 get_details_operation.cancel();
1482 }
1483
1484-TEST_F(IndexTest, testGetBaseUrl)
1485+TEST_F(SimpleIndexTest, testGetBaseUrl)
1486 {
1487 const char *value = getenv(click::SEARCH_BASE_URL_ENVVAR.c_str());
1488 if (value != NULL) {
1489@@ -592,7 +646,7 @@
1490
1491 }
1492
1493-TEST_F(IndexTest, testGetBaseUrlFromEnv)
1494+TEST_F(SimpleIndexTest, testGetBaseUrlFromEnv)
1495 {
1496 ASSERT_TRUE(setenv(click::SEARCH_BASE_URL_ENVVAR.c_str(),
1497 FAKE_SERVER.c_str(), 1) == 0);
1498@@ -600,14 +654,14 @@
1499 ASSERT_TRUE(unsetenv(click::SEARCH_BASE_URL_ENVVAR.c_str()) == 0);
1500 }
1501
1502-TEST_F(IndexTest, testPackageListsFromJsonNodeNoRecommends)
1503+TEST_F(SimpleIndexTest, testPackageListsFromJsonNodeNoRecommends)
1504 {
1505 auto lists = indexPtr->package_lists_from_json(FAKE_JSON_SEARCH_RESULT_ONE);
1506 EXPECT_EQ(1, lists.first.size());
1507 EXPECT_EQ(0, lists.second.size());
1508 }
1509
1510-TEST_F(IndexTest, testPackageListsFromJsonNodeHasRecommends)
1511+TEST_F(SimpleIndexTest, testPackageListsFromJsonNodeHasRecommends)
1512 {
1513 auto lists = indexPtr->package_lists_from_json(FAKE_JSON_SEARCH_RESULT_RECOMMENDS);
1514 EXPECT_EQ(1, lists.second.size());
1515@@ -668,3 +722,15 @@
1516 EXPECT_NE(std::string::npos, hdrs["X-Ubuntu-Frameworks"].find(fake_fwk_1));
1517 EXPECT_NE(std::string::npos, hdrs["X-Ubuntu-Frameworks"].find(fake_fwk_2));
1518 }
1519+
1520+TEST_F(QueryStringTest, testBuildHeadersFrameworksEmpty)
1521+{
1522+ EXPECT_CALL(*configPtr, get_architecture()).Times(1).WillOnce(Return(fake_arch));
1523+ EXPECT_CALL(*configPtr, get_available_frameworks())
1524+ .Times(1)
1525+ .WillOnce(Return(std::vector<std::string>{}));
1526+ auto hdrs = indexPtr->build_headers();
1527+ EXPECT_EQ(std::string::npos, hdrs["X-Ubuntu-Frameworks"].find(fake_fwk_1));
1528+ EXPECT_EQ(std::string::npos, hdrs["X-Ubuntu-Frameworks"].find(fake_fwk_2));
1529+ ASSERT_NE(std::string::npos, hdrs["X-Ubuntu-Frameworks"].find("none"));
1530+}
1531
1532=== modified file 'libclickscope/tests/test_pay.cpp'
1533--- libclickscope/tests/test_pay.cpp 2016-06-30 20:42:56 +0000
1534+++ libclickscope/tests/test_pay.cpp 2016-09-21 14:55:05 +0000
1535@@ -68,7 +68,7 @@
1536 TEST_F(PayTest, testPayPackageRefundCalled)
1537 {
1538 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1539- auto response = responseForReply(reply.asSharedPtr());
1540+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1541
1542 EXPECT_CALL(*package, do_pay_package_refund("foo")).Times(1);
1543 EXPECT_FALSE(package->refund("foo"));
1544@@ -77,7 +77,7 @@
1545 TEST_F(PayTest, testPayPackageRefundNotCalledIfCallbackExists)
1546 {
1547 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1548- auto response = responseForReply(reply.asSharedPtr());
1549+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1550
1551 std::string callback_id = std::string{"foo"} + pay::APPENDAGE_REFUND;
1552 package->callbacks[callback_id] = [](const std::string&, bool) {};
1553@@ -88,7 +88,7 @@
1554 TEST_F(PayTest, testRefundReturnsTrueForPurchasedItem)
1555 {
1556 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1557- auto response = responseForReply(reply.asSharedPtr());
1558+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1559
1560 package->success = true;
1561 EXPECT_CALL(*package, do_pay_package_refund("foo")).Times(1);
1562@@ -98,7 +98,7 @@
1563 TEST_F(PayTest, testPayPackageVerifyCalled)
1564 {
1565 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1566- auto response = responseForReply(reply.asSharedPtr());
1567+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1568
1569 EXPECT_CALL(*package, do_pay_package_verify("foo")).Times(1);
1570 EXPECT_FALSE(package->verify("foo"));
1571@@ -107,7 +107,7 @@
1572 TEST_F(PayTest, testPayPackageVerifyNotCalledIfCallbackExists)
1573 {
1574 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1575- auto response = responseForReply(reply.asSharedPtr());
1576+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1577
1578 std::string callback_id = std::string{"foo"} + pay::APPENDAGE_VERIFY;
1579 package->callbacks[callback_id] = [](const std::string&, bool) {};
1580@@ -118,7 +118,7 @@
1581 TEST_F(PayTest, testVerifyReturnsTrueForPurchasedItem)
1582 {
1583 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1584- auto response = responseForReply(reply.asSharedPtr());
1585+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1586
1587 package->success = true;
1588 EXPECT_CALL(*package, do_pay_package_verify("foo")).Times(1);
1589@@ -128,7 +128,7 @@
1590 TEST_F(PayTest, testGetPurchasesCallsWebservice)
1591 {
1592 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1593- auto response = responseForReply(reply.asSharedPtr());
1594+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1595
1596 EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
1597 .Times(1)
1598@@ -140,7 +140,7 @@
1599 TEST_F(PayTest, testGetPurchasesSendsCorrectPath)
1600 {
1601 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1602- auto response = responseForReply(reply.asSharedPtr());
1603+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1604
1605 EXPECT_CALL(*clientPtr, callImpl(EndsWith(pay::PURCHASES_API_PATH),
1606 _, _, _, _, _))
1607@@ -153,7 +153,7 @@
1608 TEST_F(PayTest, testGetPurchasesCallbackCalled)
1609 {
1610 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1611- auto response = responseForReply(reply.asSharedPtr());
1612+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1613
1614 QByteArray fake_json("[]");
1615 EXPECT_CALL(reply.instance, readAll())
1616@@ -173,7 +173,7 @@
1617 TEST_F(PayTest, testGetPurchasesEmptyJsonIsParsed)
1618 {
1619 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1620- auto response = responseForReply(reply.asSharedPtr());
1621+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1622
1623 QByteArray fake_json("[]");
1624 EXPECT_CALL(reply.instance, readAll())
1625@@ -194,7 +194,7 @@
1626 TEST_F(PayTest, testGetPurchasesSingleJsonIsParsedNullTimestamp)
1627 {
1628 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1629- auto response = responseForReply(reply.asSharedPtr());
1630+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1631
1632 QByteArray fake_json(FAKE_PURCHASES_LIST_JSON_NULL_TIMESTAMP);
1633 EXPECT_CALL(reply.instance, readAll())
1634@@ -215,7 +215,7 @@
1635 TEST_F(PayTest, testGetPurchasesTimestampIsParsed)
1636 {
1637 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1638- auto response = responseForReply(reply.asSharedPtr());
1639+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1640
1641 QByteArray fake_json(FAKE_PURCHASES_LIST_JSON);
1642 EXPECT_CALL(reply.instance, readAll())
1643@@ -237,7 +237,7 @@
1644 TEST_F(PayTest, testGetPurchasesIsCancellable)
1645 {
1646 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1647- auto response = responseForReply(reply.asSharedPtr());
1648+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1649
1650 EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
1651 .Times(1)
1652
1653=== modified file 'libclickscope/tests/test_preview.cpp'
1654--- libclickscope/tests/test_preview.cpp 2016-07-13 20:30:09 +0000
1655+++ libclickscope/tests/test_preview.cpp 2016-09-21 14:55:05 +0000
1656@@ -1,5 +1,5 @@
1657 /*
1658- * Copyright (C) 2014 Canonical Ltd.
1659+ * Copyright (C) 2014-2016 Canonical Ltd.
1660 *
1661 * This program is free software: you can redistribute it and/or modify it
1662 * under the terms of the GNU General Public License version 3, as published
1663@@ -64,7 +64,7 @@
1664 FakeIndex() {
1665
1666 }
1667- click::web::Cancellable get_details(const std::string& /*package_name*/, std::function<void(click::PackageDetails, Error)> callback, bool) override {
1668+ click::web::Cancellable get_details(const std::string& /*package_name*/, std::function<void(click::PackageDetails, Error)> callback, bool, bool) override {
1669 callback(click::PackageDetails(), Error::NetworkError);
1670 return click::web::Cancellable();
1671 }
1672
1673=== modified file 'libclickscope/tests/test_reviews.cpp'
1674--- libclickscope/tests/test_reviews.cpp 2016-05-10 13:42:12 +0000
1675+++ libclickscope/tests/test_reviews.cpp 2016-09-21 14:55:05 +0000
1676@@ -140,7 +140,7 @@
1677 TEST_F(ReviewsTest, testFetchReviewsCallsWebservice)
1678 {
1679 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1680- auto response = responseForReply(reply.asSharedPtr());
1681+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1682
1683 EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
1684 .Times(1)
1685@@ -153,7 +153,7 @@
1686 TEST_F(ReviewsTest, testFetchReviewsDoesNotSignCall)
1687 {
1688 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1689- auto response = responseForReply(reply.asSharedPtr());
1690+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1691
1692 EXPECT_CALL(*clientPtr, callImpl(_, _, false, _, _, _))
1693 .Times(1)
1694@@ -166,7 +166,7 @@
1695 TEST_F(ReviewsTest, testFetchReviewsSendsQueryAsParam)
1696 {
1697 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1698- auto response = responseForReply(reply.asSharedPtr());
1699+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1700
1701 click::web::CallParams params;
1702 params.add(click::REVIEWS_QUERY_ARGNAME, FAKE_PACKAGENAME);
1703@@ -181,7 +181,7 @@
1704 TEST_F(ReviewsTest, testFetchReviewsSendsCorrectPath)
1705 {
1706 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1707- auto response = responseForReply(reply.asSharedPtr());
1708+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1709
1710 EXPECT_CALL(*clientPtr, callImpl(EndsWith(click::REVIEWS_API_PATH),
1711 _, _, _, _, _))
1712@@ -195,7 +195,7 @@
1713 TEST_F(ReviewsTest, testFetchReviewsCallbackCalled)
1714 {
1715 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1716- auto response = responseForReply(reply.asSharedPtr());
1717+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1718
1719 QByteArray fake_json("[]");
1720 EXPECT_CALL(reply.instance, readAll())
1721@@ -216,7 +216,7 @@
1722 TEST_F(ReviewsTest, testFetchReviewsNot200)
1723 {
1724 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1725- auto response = responseForReply(reply.asSharedPtr());
1726+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1727
1728 EXPECT_CALL(reply.instance, attribute(_)).WillOnce(Return(QVariant(301)));
1729 EXPECT_CALL(reply.instance, readAll())
1730@@ -238,7 +238,7 @@
1731 TEST_F(ReviewsTest, testFetchReviewsEmptyJsonIsParsed)
1732 {
1733 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1734- auto response = responseForReply(reply.asSharedPtr());
1735+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1736
1737 QByteArray fake_json("[]");
1738 EXPECT_CALL(reply.instance, attribute(_)).WillOnce(Return(QVariant(200)));
1739@@ -261,7 +261,7 @@
1740 TEST_F(ReviewsTest, testFetchReviewsSingleJsonIsParsed)
1741 {
1742 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1743- auto response = responseForReply(reply.asSharedPtr());
1744+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1745
1746 QByteArray fake_json(FAKE_JSON_REVIEWS_RESULT_ONE.c_str());
1747 EXPECT_CALL(reply.instance, attribute(_)).WillOnce(Return(QVariant(200)));
1748@@ -295,7 +295,7 @@
1749 TEST_F(ReviewsTest, testFetchReviewsNetworkErrorReported)
1750 {
1751 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1752- auto response = responseForReply(reply.asSharedPtr());
1753+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1754
1755 EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
1756 .Times(1)
1757@@ -318,7 +318,7 @@
1758 TEST_F(ReviewsTest, testFetchReviewsIsCancellable)
1759 {
1760 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1761- auto response = responseForReply(reply.asSharedPtr());
1762+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1763
1764 EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, _))
1765 .Times(1)
1766@@ -333,7 +333,7 @@
1767 TEST_F(ReviewsTest, testSubmitReviewIsCancellable)
1768 {
1769 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1770- auto response = responseForReply(reply.asSharedPtr());
1771+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1772
1773 click::Review review;
1774 review.rating = 3;
1775@@ -354,7 +354,7 @@
1776 TEST_F(ReviewsTest, testSubmitReviewUtf8)
1777 {
1778 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1779- auto response = responseForReply(reply.asSharedPtr());
1780+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1781
1782 click::Review review;
1783 review.rating = 3;
1784@@ -378,7 +378,7 @@
1785 TEST_F(ReviewsTest, testSubmitReviewLanguageCorrect)
1786 {
1787 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1788- auto response = responseForReply(reply.asSharedPtr());
1789+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1790
1791 click::Review review;
1792 review.rating = 3;
1793@@ -402,7 +402,7 @@
1794 TEST_F(ReviewsTest, testSubmitReviewLanguageCorrectForFullLangCodes)
1795 {
1796 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1797- auto response = responseForReply(reply.asSharedPtr());
1798+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1799
1800 click::Review review;
1801 review.rating = 3;
1802@@ -428,7 +428,7 @@
1803 TEST_F(ReviewsTest, testEditReviewUrlHasReviewId)
1804 {
1805 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1806- auto response = responseForReply(reply.asSharedPtr());
1807+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1808
1809 click::Review review;
1810 review.id = 1234;
1811@@ -448,7 +448,7 @@
1812 TEST_F(ReviewsTest, testEditReviewIsCancellable)
1813 {
1814 LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
1815- auto response = responseForReply(reply.asSharedPtr());
1816+ auto response = MockClient::responseForReply(reply.asSharedPtr());
1817
1818 click::Review review;
1819 review.id = 1234;
1820
1821=== modified file 'scope/clickstore/store-query.cpp'
1822--- scope/clickstore/store-query.cpp 2016-09-21 14:55:05 +0000
1823+++ scope/clickstore/store-query.cpp 2016-09-21 14:55:05 +0000
1824@@ -169,6 +169,7 @@
1825 click::HighlightList& highlights;
1826 scopes::SearchMetadata meta;
1827 click::web::Cancellable search_operation;
1828+ click::web::Cancellable search_snaps_operation;
1829 click::web::Cancellable purchases_operation;
1830 pay::Package& pay_package;
1831 std::shared_future<void> qt_ready_;
1832@@ -196,6 +197,7 @@
1833 {
1834 qDebug() << "cancelling search of" << QString::fromStdString(query().query_string());
1835 impl->search_operation.cancel();
1836+ impl->search_snaps_operation.cancel();
1837 }
1838
1839 click::Interface& click::Query::clickInterfaceInstance()
1840@@ -290,7 +292,12 @@
1841 res.set_title(pkg.title);
1842 res.set_art(pkg.icon_url);
1843 res.set_uri(pkg.url);
1844- res[click::Query::ResultKeys::NAME] = pkg.name;
1845+ res["snap_id"] = pkg.snap_id;
1846+ if (pkg.snap_id.empty()) {
1847+ res[click::Query::ResultKeys::NAME] = pkg.name;
1848+ } else {
1849+ res[click::Query::ResultKeys::NAME] = pkg.alias;
1850+ }
1851 res["subtitle"] = pkg.publisher;
1852 auto installed = installedPackages.find(pkg);
1853
1854@@ -533,6 +540,7 @@
1855 push_package(searchReply, recommendsCategory,
1856 installedPackages, r);
1857 }
1858+
1859 qDebug() << "search completed";
1860 this->finished(searchReply); //FIXME: this shouldn't be needed
1861 };
1862@@ -596,7 +604,37 @@
1863 {
1864 qDebug() << "starting search of" << QString::fromStdString(query().query_string());
1865 push_departments(searchReply);
1866- impl->search_operation = impl->index.search(query().query_string(), query().department_id(), search_cb, force_cache);
1867+ impl->search_operation = impl->index.search
1868+ (query().query_string(), query().department_id(),
1869+ [this, search_cb, force_cache](Packages packages,
1870+ Packages recommends) {
1871+ if (Configuration().is_snapd_running()) {
1872+ qDebug() << "Searching for snaps too.";
1873+ impl->search_snaps_operation = impl->index.search_snaps
1874+ (query().query_string(),
1875+ [this, packages, recommends, search_cb](Packages snap_packages,
1876+ Packages snap_recommends) {
1877+ qDebug() << "In the callback.";
1878+ Packages new_packages, new_recommends;
1879+ for (const auto& p: packages) {
1880+ new_packages.push_back(p);
1881+ }
1882+ for (const auto& p: snap_packages) {
1883+ new_packages.push_back(p);
1884+ }
1885+ for (const auto& r: recommends) {
1886+ new_recommends.push_back(r);
1887+ }
1888+ for (const auto& r: snap_recommends) {
1889+ new_recommends.push_back(r);
1890+ }
1891+ qDebug() << "Snaps appended.";
1892+ search_cb(new_packages, new_recommends);
1893+ }, force_cache);
1894+ } else {
1895+ search_cb(packages, recommends);
1896+ }
1897+ }, force_cache);
1898 }
1899 }
1900 });

Subscribers

People subscribed via source and target branches

to all changes: