Merge lp:~paulliu/unity-scope-click/showratings into lp:unity-scope-click

Proposed by dobey
Status: Merged
Approved by: dobey
Approved revision: 105
Merged at revision: 104
Proposed branch: lp:~paulliu/unity-scope-click/showratings
Merge into: lp:unity-scope-click
Diff against target: 394 lines (+307/-3)
6 files modified
src/Makefile.am (+2/-1)
src/click-scope.vala (+7/-1)
src/click-webservice.vala (+7/-1)
src/fake-data.vala (+43/-0)
src/rnrclient.vala (+201/-0)
src/test-click-webservice.vala (+47/-0)
To merge this branch: bzr merge lp:~paulliu/unity-scope-click/showratings
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
dobey (community) Approve
Manuel de la Peña (community) Approve
Review via email: mp+198762@code.launchpad.net

This proposal supersedes a proposal from 2013-12-10.

Commit message

Get the reviews from the server and pass them to the preview.

Description of the change

Provide reviews/ratings from server in previews.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
Manuel de la Peña (mandel) wrote : Posted in a previous version of this proposal

Can you explain what is the following line doing:

var reviews = yield rnrClient.get_reviews("","any","any","any","any",details.title,"1","helpful");

Is "any" some kind of keyword??? Should we use a constant?

We have the following var names:

node1, node2, gvar1

Can we use names that add some information to the reviewer, I have no context of what the data should be and such names do not help. Maybe something like rootNode, ratingNode etc...?

Should we log something in this exception:

182 + try {
183 + gvar1 = Json.gvariant_deserialize(node1.get_member(node2),null);
184 + } catch (GLib.Error e) {
185 + continue;
186 + }

It might be a good thing to do when debugging and I do not trust the server side not changing things or always working ;)

Why do you use in some cases the var keyword and in others you do not? For example:

143 + Rest.Proxy proxy = new Rest.Proxy(REVIEWS_URL, false);
144 + var call = proxy.new_call();

Could not have used bar in both cases?

In the following code:

257 + try {
258 + parser.load_from_data(testData1);
259 + } catch (GLib.Error e) {
260 + }

It might be a good idea to deal with the exception in case some other developer changes the testData wrongly and has bad results in the tests, what do you think???

All the rest of the code looks great, thx!!!

review: Needs Fixing
Revision history for this message
dobey (dobey) wrote : Posted in a previous version of this proposal

48 + --pkg rest-0.7 \

I thought we agreed to not use librest, but just use soup for everything?

Also, the test doesn't seem to actually test anything, as I read it. It's fake data in a JSON dict, and you parse it as such. We don't need to write unit tests for json-glib in our code. It's also a bit weird to define a test method inside a fake class, and simply have the actual test method call that method, doing the assertion inside the fake class. Fake classes should really only be used to override methods which require network or dbus access to other daemons, to prevent such access and isolate the tests. Fake data should probably be placed in external files for use in the tests, or at the very least, encoded in the fake-data.vala source file. And the actual test and assertion should happen within the test function itself, not inside a set of methods in another class.

review: Needs Fixing
Revision history for this message
dobey (dobey) wrote : Posted in a previous version of this proposal

118 + const string REVIEWS_URL = "http://reviews.ubuntu.com/reviews/api/1.0";

Also, this needs to be HTTPS, and should be split up such that the base URL can be changed via environment variable, for testing against staging. See click-webservice.vala for how we do this for the SSO base URL.

Revision history for this message
Ying-Chun Liu (paulliu) wrote : Posted in a previous version of this proposal

I'll rewrite it to use libsoup because I really cannot make the SSO work with librest.

But maybe we want to use librest for the future at some time as it makes the code cleaner and easier to be maintained?

Revision history for this message
Ying-Chun Liu (paulliu) wrote : Posted in a previous version of this proposal

the reviews retriviing doesn't need the SSO. So I'll keep the http here.
The submit reviews function will be implemented in another branch which will use https.

Revision history for this message
dobey (dobey) wrote : Posted in a previous version of this proposal

77 + const string REVIEWS_BASE_URL = "http://reviews.ubuntu.com/reviews/api/1.0";

86 + string from_environ (string env_name, string default_value) {
87 + string env_value = Environment.get_variable (env_name);
88 + return env_value != null ? env_value : default_value;
89 + }
90 +
91 + string get_base_url () {
92 + return from_environ ("U1_REVIEWS_BASE_URL", REVIEWS_BASE_URL);
93 + }

This is still wrong. Why are you not using HTTPS here? Also, the _BASE_URL should only be "https://reviews.ubuntu.com/reviews" with "/api/1.0" added after. One shouldn't include the "/api/1.0" portion in the environment variable. If someone passes /api/2.0 for example, the app wouldn't handle it.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Approve (continuous-integration)
Revision history for this message
dobey (dobey) wrote : Posted in a previous version of this proposal

130 + public async Variant? get_reviews(string packagename, string? language,
131 + string? origin, string? distroseries,
132 + string? version, string appname,
133 + string page, string sort) {

I wonder if we can abstract all these arguments to a new object, or just pass in the AppDetails object here, and get the language internally rather than taking an argument for it. It's better to have an object containing a bunch of args, than to pass many options individually like this.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:91
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~paulliu/unity-scope-click/showratings/+merge/198762/+edit-commit-message

http://jenkins.qa.ubuntu.com/job/unity-scope-click-ci/125/
Executed test runs:
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-scope-click-trusty-amd64-ci/23
    SUCCESS: http://jenkins.qa.ubuntu.com/job/unity-scope-click-trusty-armhf-ci/23

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/unity-scope-click-ci/125/rebuild

review: Needs Fixing (continuous-integration)
92. By Ying-Chun Liu

remvoe server-status as we don't need to use it.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
dobey (dobey) wrote :

The ReviewFilter object is a little weird (maybe because of the name). You aren't documenting in the code what each element does, or why its value is what it is. For example, it's still not clear why "any" is used in several places, or why you are passing "any" as the version, instead of the version.

A guess suggests this tells the server that we don't care what distroseries/version/etc… the reviews are for. But this seems like something that should be handled properly on the server side, and not the client. In other words, the client should send all available data about the package we want to see reviews for, and then the server should make an intelligent decision on what to return. If this isn't giving us useful data, then we should still do the right thing, and file bugs against the server, for it to do the right thing as well.

93. By Ying-Chun Liu

Add comments.

Revision history for this message
Michael Nelson (michael.nelson) wrote :

I don't remember why "any" was chosen as the token, but from memory a token was chosen so that the urls would be consistent, flexible and without qparams - at the expense of requiring multiple requests in some cases. So no, there is currently no intelligence for "you requested version X, but we don't have reviews of that, so here are the reviews of X".

Looking at the interface document [1], the get_reviews helper is just enabling requests in the form:

/api/2.0/reviews/filter/lang/origin/distroseries/version/packagename/

ie. in the first example:
>>> skype_reviews = api.get_reviews(packagename='skype')

results in a call to:

/api/2.0/reviews/filter/any/any/any/any/skype/

ie - all reviews of skype across all distroseries, versions etc.

The second example: api.get_reviews(packagename='skype', version='4.1.0.20.0-0ubuntu0.13.04.2')

in (an escaped)

/api/2.0/reviews/filter/any/any/distroseries/4.1.0.20.0-0ubuntu0.13.04.2/skype/

ie. all reviews of that version of skype, across distroseries etc.

So it's flexible, but means that multiple requests may be needed to do things like "get me the reviews for skype and somotherapp, or get me reviews of skype versions X and Y, or something intelligent like "You asked for version X, but here's reviews for X-1.

The server could be easily updated to support that if you know exactly what you want. If you have specific requests like this that you know you'll need often, it should be trivial to add those to the API.

Hope that helps!
[1] https://wiki.ubuntu.com/AppStore/Interfaces/RatingsAndReviews

Revision history for this message
Michael Nelson (michael.nelson) wrote :

> I don't remember why "any" was chosen as the token, but from memory a token
> was chosen so that the urls would be consistent, flexible and without qparams
> - at the expense of requiring multiple requests in some cases. So no, there is
> currently no intelligence for "you requested version X, but we don't have
> reviews of that, so here are the reviews of X".

X-1, sorry.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
94. By Ying-Chun Liu

Change origin to "click".

95. By Ying-Chun Liu

Merge upstream.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Manuel de la Peña (mandel) wrote :

Looks good to me

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
dobey (dobey) wrote :

+ return get_base_url() + "/api/1.0/reviews/filter/%s/%s/%s/%s/%s%s/page/%s/%s/";

I'm confused by this. Particularly the "%s%s" in the middle there, and the apparent need for paging to support having the server sort the results.

Why are you combining packagename and appname into a single string there? I don't think we should be doing that. I also don't think we should be using pagination. If the results from the API include the usefulness rating, we can just do the sorting on that locally, and avoid passing the extra weird parameters.

217 + * @origin: Normally comes from "ubuntu". For click packages it is "click".
218 + * The default value "any" to get reviews for any origin.
+ filter.origin = "click";

Why are we using "click" here? The origin is not click. The origin for packages in Ubuntu itself is "ubuntu" because they are packaged as part of the Ubuntu archive, by Ubuntu developers. Packages which are sold via MyApps in the Software Center, do not have an origin of "ubuntu" there. Rather, "steam" for example, has an origin of "valve inc." (which is apparently not a proper origin ID, but that's another issue). The origin is supposed to be who created the package and uploaded it (aka, the Publisher). I don't know that we have a proper ID for publishers though, which is in the app details, and which is not a user-displayable string, but rather is a string without any spaces. However, I'm pretty sure "click" is not what we want to use there.

33 + if (reviews != null) {
34 + preview.add_info(new Unity.InfoHint.with_variant(HINT_REVIEWS, LABEL_REVIEWS, null, reviews));
35 + debug("Add reviews "+reviews.print(true));
36 + }

4 spaces for indents please, not 2.

review: Needs Fixing
Revision history for this message
dobey (dobey) wrote :

Some tests would also be nice to have here.

96. By Ying-Chun Liu

fix indent

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michael Nelson (michael.nelson) wrote :

> + return get_base_url() +
> "/api/1.0/reviews/filter/%s/%s/%s/%s/%s%s/page/%s/%s/";
>
> I'm confused by this. Particularly the "%s%s" in the middle there, and the
> apparent need for paging to support having the server sort the results.

Hrm - I assume vala/C++ printf doesn't support a hash of args so you can return something like: ".../filter/%(lang)s/%(origin)s/%(distroseries)s/...")? That would be clearer.

>
> Why are you combining packagename and appname into a single string there? I
> don't think we should be doing that.

Correct - it should just be packagename (according to the urls in rnr server [1]).

[1] http://bazaar.launchpad.net/~rnr-developers/rnr-server/trunk/view/head:/src/reviewsapp/api/urls.py#L122

You should expect to see a 404 if you combine the packagename+appname like that.

> I also don't think we should be using
> pagination. If the results from the API include the usefulness rating, we can
> just do the sorting on that locally, and avoid passing the extra weird
> parameters.

You don't need to use the pagination unless you want more than the first page of results. By default, the server will return the first batch of results, sorted by usefulness (and the current config of the server has the batch size at 10 results). These were the requirements that we had for USC client, but can be changed as needed. As far as I can tell below, you're never using anything but the default first page with the default sort of usefulness.

>
>
> 217 + * @origin: Normally comes from "ubuntu". For click packages it is
> "click".
> 218 + * The default value "any" to get reviews for any origin.
> + filter.origin = "click";
>
> Why are we using "click" here? The origin is not click. The origin for
> packages in Ubuntu itself is "ubuntu" because they are packaged as part of the
> Ubuntu archive, by Ubuntu developers.

Correct, the origin should be "ubuntu" here, while the distroseries should be "click" (there is no natty/precise/etc. for click packages - at least, that's the decision that was made for exporting the apps from devportal [2]:

[2] http://software-center.ubuntu.com/api/2.0/applications/en/ubuntu/click/

I don't see why this unity-scope wouldn't just use the default for ReviewFilter of ubuntu/click?

> Packages which are sold via MyApps in
> the Software Center, do not have an origin of "ubuntu" there. Rather, "steam"
> for example, has an origin of "valve inc." (which is apparently not a proper
> origin ID, but that's another issue). The origin is supposed to be who created
> the package and uploaded it (aka, the Publisher). I don't know that we have a
> proper ID for publishers though, which is in the app details, and which is not
> a user-displayable string, but rather is a string without any spaces. However,
> I'm pretty sure "click" is not what we want to use there.

Right. For USC, the origin is either ubuntu or the private ppa identifier (url-encoded).

Hope that helps!

Revision history for this message
dobey (dobey) wrote :

> > + return get_base_url() +
> > "/api/1.0/reviews/filter/%s/%s/%s/%s/%s%s/page/%s/%s/";
> >
> Hrm - I assume vala/C++ printf doesn't support a hash of args so you can
> return something like: ".../filter/%(lang)s/%(origin)s/%(distroseries)s/...")?
> That would be clearer.

I don't think it would be made clearer. The most confusing part was the "%s%s" (without a slash between them), which we agree is wrong. I think a simple comment that explains the structure of the URL would be enough to clarify what each %s is, in the string. The Python string formatting would obviously be better, but we can't do that in C/Vala, so a comment would be well enough.

> Correct, the origin should be "ubuntu" here, while the distroseries should be
> "click" (there is no natty/precise/etc. for click packages - at least, that's
> the decision that was made for exporting the apps from devportal [2]:
>
> [2] http://software-center.ubuntu.com/api/2.0/applications/en/ubuntu/click/
>
> I don't see why this unity-scope wouldn't just use the default for
> ReviewFilter of ubuntu/click?

Well, this doesn't make sense to me either. The origin isn't Ubuntu (ie, these packages aren't part of the Ubuntu archive, but are published by other individuals or organizations). So, I don't think we should be defaulting to anything, but instead getting some value from the details of the package, and using that as the origin. Maybe we need to add something to the package details endpoint of the click-package-index API to do that. Also, I think the distroseries does need to be the actual distroseries here. But maybe we should be using the "click_framework" value from the package details here, rather than saucy/trusty/etc… ?

Revision history for this message
Michael Nelson (michael.nelson) wrote :

On Thu, Jan 2, 2014 at 4:55 PM, Rodney Dawes <email address hidden> wrote:
>> Correct, the origin should be "ubuntu" here, while the distroseries should be
>> "click" (there is no natty/precise/etc. for click packages - at least, that's
>> the decision that was made for exporting the apps from devportal [2]:
>>
>> [2] http://software-center.ubuntu.com/api/2.0/applications/en/ubuntu/click/
>>
>> I don't see why this unity-scope wouldn't just use the default for
>> ReviewFilter of ubuntu/click?
>
> Well, this doesn't make sense to me either. The origin isn't Ubuntu (ie, these packages aren't part of the Ubuntu archive, but are published by other individuals or organizations).

Hrm - true. So for existing reviews, the origin is the ppa identifier,
such as lp-ppa-commercial-ppa-uploaders-uberwriter.

For click packages, we have a packagename which includes an 'origin'
of sorts, like:

com.ubuntu.developer.victorsemyonov.mymaps

So I wonder if it'd make sense to use:

origin: com.ubuntu.developer.victorsemyonov
packagename: mymaps

in that case? Let me know, as I'll need to update the server (easy enough).

> So, I don't think we should be defaulting to anything, but instead getting some value from the details of the package, and using that as the origin. Maybe we need to add something to the package details endpoint of the click-package-index API to do that.

As above, the 'domain' seems to map 1:1 with the idea of origin?

> Also, I think the distroseries does need to be the actual distroseries here. But maybe we should be using the "click_framework" value from the package details here, rather than saucy/trusty/etc… ?

Yep, +1 to using the click_framework for the distroseries. I can get
an MP ready with those changes for the server. So, to check my
understanding with a summary:

You'll search/filter with origin: any, distroseries: ubuntu-sdk-13.10

You'll submit reviews with:
origin: com.ubuntu.developer.victorsemyonov
packagename: mymaps
distroseries: ubuntu-sdk-13.10

Will you need to search for click packages across frameworks? If so,
it'll need a bit more work to make that clean (as origin:any,
distroseries: any will give you not just click packages, but normal
packages also - a result of us just re-using the existing
infrastructure)., but if not, the above should be fine.

Let me know if you want to have a call about this.

Revision history for this message
Ying-Chun Liu (paulliu) wrote :

> On Thu, Jan 2, 2014 at 4:55 PM, Rodney Dawes <email address hidden>
> wrote:
> >> Correct, the origin should be "ubuntu" here, while the distroseries should
> be
> >> "click" (there is no natty/precise/etc. for click packages - at least,
> that's
> >> the decision that was made for exporting the apps from devportal [2]:
> >>
> >> [2] http://software-center.ubuntu.com/api/2.0/applications/en/ubuntu/click/
> >>
> >> I don't see why this unity-scope wouldn't just use the default for
> >> ReviewFilter of ubuntu/click?
> >
> > Well, this doesn't make sense to me either. The origin isn't Ubuntu (ie,
> these packages aren't part of the Ubuntu archive, but are published by other
> individuals or organizations).
>
> Hrm - true. So for existing reviews, the origin is the ppa identifier,
> such as lp-ppa-commercial-ppa-uploaders-uberwriter.
>
> For click packages, we have a packagename which includes an 'origin'
> of sorts, like:
>
> com.ubuntu.developer.victorsemyonov.mymaps
>
> So I wonder if it'd make sense to use:
>
> origin: com.ubuntu.developer.victorsemyonov
> packagename: mymaps
>
> in that case? Let me know, as I'll need to update the server (easy enough).
>
> > So, I don't think we should be defaulting to anything, but instead getting
> some value from the details of the package, and using that as the origin.
> Maybe we need to add something to the package details endpoint of the click-
> package-index API to do that.
>
> As above, the 'domain' seems to map 1:1 with the idea of origin?
>

yeah, I think this is a good idea.We just need a 1:1 mapping to query the reviews.
I mean, we just give you a key and you give us all of the data.
origin+packagename should be good enough for being a key I think.

Revision history for this message
dobey (dobey) wrote :

> For click packages, we have a packagename which includes an 'origin'
> of sorts, like:
>
> com.ubuntu.developer.victorsemyonov.mymaps
>
> So I wonder if it'd make sense to use:
>
> origin: com.ubuntu.developer.victorsemyonov
> packagename: mymaps
>
> in that case? Let me know, as I'll need to update the server (easy enough).

While this is common, it's not necessarily required to be this way. I'm not sure we want to split this string up in this way at all. The package name is the full string, not just the text after the last '.' character. It's possible that this portion may conflict (multiple people might write a 'flickr' app for example). It could result in requests for existing reviews, returning the wrong things (reviews for the other app with the same name).

Maybe the best solution, given the data we have, is to simply use the package name as the origin and the package name.

> > So, I don't think we should be defaulting to anything, but instead getting
> some value from the details of the package, and using that as the origin.
> Maybe we need to add something to the package details endpoint of the click-
> package-index API to do that.
>
> As above, the 'domain' seems to map 1:1 with the idea of origin?

There is no 'domain' exactly. But I think we can use the package name for both the origin and the package name, to introduce the necessary level of uniqueness.

> So, to check my understanding with a summary:
>
> You'll search/filter with origin: any, distroseries: ubuntu-sdk-13.10
>
> You'll submit reviews with:
> origin: com.ubuntu.developer.victorsemyonov
> packagename: mymaps
> distroseries: ubuntu-sdk-13.10

As mentioned above, I don't think we'll do it this way, but we should probably use full package name (com.example.foo.bar) for both origin and package name. I also don't think we want to search for "any" in the origin, ever. We should only get reviews for the package that has the correct origin for the package.

> Will you need to search for click packages across frameworks? If so,
> it'll need a bit more work to make that clean (as origin:any,
> distroseries: any will give you not just click packages, but normal
> packages also - a result of us just re-using the existing
> infrastructure)., but if not, the above should be fine.

I'd like to say no for now, and we can deal with making that possible later, if necessary.

Revision history for this message
dobey (dobey) wrote :

98 + return get_base_url() + "/api/1.0/reviews/filter/%s/%s/%s/%s/%s%s/page/%s/%s/";

Please add a comment above this line, explaining which each %s is for exactly. Also, please switch to using the simpler URL, and avoid the "%s%s" combining the filter.packagename and filter.appname into a single part of the URL's path. We should be using "/api/1.0//reviews/filter/%s/%s/%s/%s/%s/" with "language, origin, distroseries, version, packagename" as the format values. The origin and packagename arguments should be the same here (using the package_name value from AppDetails), version should be version from AppDetails, and distroseries should be the "framework" value from AppDetails. We should also check that origin, distroseries, version, and packagename are not the default values of "any" or "", raising an error if they are, and not getting any reviews from the server in such a case.

239 + public string appname = "";
240 + public string page = "1";
241 + public string sort = "helpful";

You can also get rid of these, as we do not need to use any of them, with the above changes.

35 + debug("Add reviews "+reviews.print(true));

Let's not just print all the reviews here. It will eventually be a lot of data to be looking at in the log. Maybe just logging "Got %d reviews for %s" with the number of reviews received, and the package name, instead.

And finally, a few tests would be nice. Especially with the above mentioned change to the URL structuring and handling of error cases, to ensure the error cases are being handled correctly, as well as the valid results cases.

Revision history for this message
Ying-Chun Liu (paulliu) wrote :

> 98 + return get_base_url() +
> "/api/1.0/reviews/filter/%s/%s/%s/%s/%s%s/page/%s/%s/";
>
> Please add a comment above this line, explaining which each %s is for exactly.
> Also, please switch to using the simpler URL, and avoid the "%s%s" combining
> the filter.packagename and filter.appname into a single part of the URL's
> path. We should be using "/api/1.0//reviews/filter/%s/%s/%s/%s/%s/" with
> "language, origin, distroseries, version, packagename" as the format values.
> The origin and packagename arguments should be the same here (using the
> package_name value from AppDetails), version should be version from
> AppDetails, and distroseries should be the "framework" value from AppDetails.
> We should also check that origin, distroseries, version, and packagename are
> not the default values of "any" or "", raising an error if they are, and not
> getting any reviews from the server in such a case.

seems to me that we currently don't have framework value in AppDetails. It is a private constant now.

97. By Ying-Chun Liu

Add some unit tests.
Partly fix the issues in comment 465611

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

The test you added created a conflict with trunk. Please merge trunk into your branch and ensure there are no conflicts (and that you don't remove any of the existing tests in trunk).

Revision history for this message
Alexander Sack (asac) wrote :

fwiw, the src/test-click-webservice.vala hunks in this MP seem to commit a merge conflict :)

Search for:
  +<<<<<<< TREE

98. By Ying-Chun Liu

Add version/framework

99. By Ying-Chun Liu

merge trunk

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
100. By Ying-Chun Liu

fix indent.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
101. By Ying-Chun Liu

fix comment for ReviewFilter.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
dobey (dobey) wrote :

67 + keywords: parse_string_list (details, JSON_FIELD_KEYWORDS),
68 + version: details.get_string_member(JSON_FIELD_VERSION),
69 + framework: parse_string_list (details, JSON_FIELD_FRAMEWORK)

Fix the spacing here please. The version and framework you added, seem to have tabs and are spaced further to the right, than the previous lines are.

58 + public string[] framework { get; construct; }
69 + framework: parse_string_list (details, JSON_FIELD_FRAMEWORK)

Why are you using this as a string list? The JSON for this seems to be a single string, not a list of strings.

338 +

Can you remove this new empty line you seem to have added?

172 + private string from_environ (string env_name, string default_value) {
177 + private string get_base_url () {
181 + private string get_review_url() {

There's no reason these need to be private. Rather, it would be a good idea to have them be public, and for there to be a few tests for them (especially to test from_environ's success and failure cases).

review: Needs Fixing
102. By Ying-Chun Liu

fix indent.
Add test for from_environ
fix framework.

Revision history for this message
Ying-Chun Liu (paulliu) wrote :

** (process:3961): DEBUG: click-webservice.vala:320: response is {"website": "http://www.wellsb.com", "description": "Port of the classic Snake game\nThe classic snake game is a great way to pass time on your Ubuntu touch mobile device. The app has full keyboard support, so it's also very enjoyable on desktop.\n\nEat cookies and grow, but don't let the skull harm you!\n\nPorted from Nokia Harmattan devices. All features from the original game have been successfully ported to the Ubuntu Touch platform.", "license": "GNU GPL v3", "framework": ["ubuntu-sdk-13.10"], "support_url": "mailto:<email address hidden>", "icon_url": "https://myapps.developer.ubuntu.com/site_media/appmedia/2013/09/snake64.png", "price": 0.0, "title": "Snake", "binary_filesize": 825144, "download_url": "https://public.apps.ubuntu.com/download/com.wellsb/snake-port/com.wellsb.snake-port_0.0.1.4_all.click", "name": "com.wellsb.snake-port", "click_version": "0.1", "date_published": "2013-09-10T19:10:19.410000", "version": "0.0.1.4", "architecture": ["all"], "terms_of_service": "", "prices": {"USD": 0.0}, "screenshot_url": "https://myapps.developer.ubuntu.com/site_media/appmedia/2013/09/snake_001_1.png", "screenshot_urls": ["https://myapps.developer.ubuntu.com/site_media/appmedia/2013/09/snake_001_1.png", "https://myapps.developer.ubuntu.com/site_media/appmedia/2013/09/snake_002_2.png"], "company_name": ""}

I saw this. Is framework really just a string?

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
103. By Ying-Chun Liu

Add 2014 to copyright.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
dobey (dobey) wrote :

Looks like the framework is a list after all in the search API (but is apparently only a string on myapps, hence the confusion). We'll probably need to get the framework to use, from the system instead of the package details, when there is a way to do that.

104. By Ying-Chun Liu

revert part of the previous commit - change back framework as string list.
Add a TODO to indicate that we should use system's framework.

Revision history for this message
Ying-Chun Liu (paulliu) wrote :

Currently I add a TODO in source.
I've talked to lool and noodles. Found that the system can also provides more than 1 framework on a single device.

To get a list of the framework that system is provided, there's some files in /usr/share/click/frameworks/*.framework provided by package "ubuntu-sdk-libs". Also there's a python class ClickInstaller._has_framework() can do this.

So we might want to do an intersect of the system's and the AppDetails' and do a multiple query and then sort the result.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michael Nelson (michael.nelson) wrote :

TBH, I don't understand why we're using framework(s) for this interaction with the reviews api service at all.

As I understand it:

1) A click package definition can define the *required* frameworks that it needs.
2) A client can support multiple frameworks
3) The client already knows which apps it can install (from querying search.apps.u.c), and will only ever (?) want to retrieve reviews for apps it knows it can install, or submit reviews for apps it has already installed.

The review api service doesn't need to care what framework(s) the app requires (that's what search.apps.u.c is for), or which frameworks the client supports.

If it helps, I can send an email to the list to get more input, but IMO, we should just be sending distroseries=click as we were originally, or what am I missing?

Revision history for this message
Roberto Alsina (ralsina) wrote :

Good point, there is no way to get to the reviews on a app with the wrong
framework, etc. This is getting way overcomplicated.

On Thu, Jan 9, 2014 at 8:52 AM, Michael Nelson <<email address hidden>
> wrote:

> TBH, I don't understand why we're using framework(s) for this interaction
> with the reviews api service at all.
>
> As I understand it:
>
> 1) A click package definition can define the *required* frameworks that it
> needs.
> 2) A client can support multiple frameworks
> 3) The client already knows which apps it can install (from querying
> search.apps.u.c), and will only ever (?) want to retrieve reviews for apps
> it knows it can install, or submit reviews for apps it has already
> installed.
>
> The review api service doesn't need to care what framework(s) the app
> requires (that's what search.apps.u.c is for), or which frameworks the
> client supports.
>
> If it helps, I can send an email to the list to get more input, but IMO,
> we should just be sending distroseries=click as we were originally, or what
> am I missing?
>
>
> --
>
> https://code.launchpad.net/~paulliu/unity-scope-click/showratings/+merge/198762
> Your team Ubuntu One hackers is subscribed to branch lp:unity-scope-click.
>

Revision history for this message
Ying-Chun Liu (paulliu) wrote :

yeah, it is a good point.
But I also can understand what dobey was worrying about.
I'll need to confirm if 1) is true.
Is that field the required framework, or just *supported* framework.
I mean if a click package can run on either 13.10 and 14.04 framework. In that case the user might only wants to get the reviews of specific framework. Because a click package might get negative reviews if it has a bug on one of the framework but good on another.

Revision history for this message
Roberto Alsina (ralsina) wrote :

Well, that's actually a design/UX question. A quick check on Play tells me
the reviews are not separated by android version, and that makes sense, or
else new versions will show no reviews at all, which is weird.

I'd say let's not filter by framework *at all* at this point.

105. By Ying-Chun Liu

use "click" as framework.

Revision history for this message
Michael Nelson (michael.nelson) wrote :

On Thu, Jan 9, 2014 at 2:05 PM, Ying-Chun Liu <email address hidden> wrote:
> yeah, it is a good point.
> But I also can understand what dobey was worrying about.
> I'll need to confirm if 1) is true.
> Is that field the required framework, or just *supported* framework.

Required AIUI. From [1]:

For future expansion (e.g. applications that require multiple
frameworks), the syntax of “framework” is formally that of a Debian
dependency relationship field. Currently, only a simple name is
permitted, e.g. “framework”: “ubuntu-sdk-13.10”.

[1] https://click.readthedocs.org/en/latest/file-format.html#manifest

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
dobey (dobey) wrote :

The framework is needed because the reviews API requires distroseries. It's required because the API is for some reason a URL path, and not a POST request to an endpoint, with some JSON to describe what we want.

Using the framework for the distroseries makes sense to me, but we can just as well use "saucy" or "trusty" or whatever the Ubuntu distroseries is, if we have that information on the device. I don't know how the reviews system on Android works or not. But it doesn't really matter, because we're not using their system. We're stuck with using the weird API we have, which requires a distroseries. The way software-center was written, was to get reviews for the "previous" series, if the current series results were empty. That should really be handled on the server side, and we really should have a proper API, but it's not.

Revision history for this message
Roberto Alsina (ralsina) wrote :

Yes, but we can just as easily use "foo" as the distroseries, forever. We
are trying to implement something here, and we control both sides of the
thing, so leaking the API into the UX is not a foregone conclusion. If
something needs to bend to make the usage reasonable, then it bends.

Having all apps lose all reviews when you update the phone is silly.

Revision history for this message
Michael Nelson (michael.nelson) wrote :

Hi Rodney, let me know if you'd rather a call, but RE the points below:

On Thu, Jan 9, 2014 at 3:22 PM, Rodney Dawes <email address hidden> wrote:
> The framework is needed because the reviews API requires distroseries. It's required because the API is for some reason a URL path, and not a POST request to an endpoint, with some JSON to describe what we want.

The request for reviews filtered by a package is a GET request to a
URL. The request for creating a new review is a POST to an endpoint
(/api/1.0/reviews/) with some JSON to describe what you want.

And yep, creating a new review requires a distroseries because it was
created for USC. We could use distroseries="click" which would enable
the server to differentiate the reviews easily (distroseries is
already indexed), or we could also quite easily create a separate
resource for click apps which doesn't have these hacks (origin and
distroseries), but this started as a way to re-use what we already
had.

>
> Using the framework for the distroseries makes sense to me, but we can just as well use "saucy" or "trusty" or whatever the Ubuntu distroseries is, if we have that information on the device. I don't know how the reviews system on Android works or not. But it doesn't really matter, because we're not using their system. We're stuck with using the weird API we have, which requires a distroseries. The way software-center was written, was to get reviews for the "previous" series, if the current series results were empty. That should really be handled on the server side, and we really should have a proper API, but it's not.
>

If it's worth creating a separate API for click (with separate specs
from what we already do for USC), then let's do that. If we want to
re-use what we've already got for USC, let's do that. That decision
isn't my call, but I do want to be able to support you whichever way
that decision goes.

Revision history for this message
Michael Nelson (michael.nelson) wrote :

On Thu, Jan 9, 2014 at 3:41 PM, Michael Nelson
<email address hidden> wrote:
>
> If it's worth creating a separate API for click (with separate specs
> from what we already do for USC), then let's do that. If we want to
> re-use what we've already got for USC, let's do that. That decision
> isn't my call, but I do want to be able to support you whichever way
> that decision goes.

FWIW, I'm doing a quick branch which I'll give to Rodney tomorrow with
an example of a separate click review API (as part of the same
service). It won't take long, and would mean we don't have to release
software on the client that has hacks to fit in with existing services
for which it wasn't designed. It'll also have the benefit that it's
easy to separate later if we need to deploy the click review service
separately.

I'm doing the following, but we can make it exactly as we see fit so
just let me know:

To create a review, it's much the same:
POST /click/api/1.0/reviews/
with the json data (same as current, just without origin or distroseries)

To retrieve reviews for a specific application:
GET /click/1.0/reviews/en/com.ubuntu.developer.dholbach.webapp-bvg/

Or, if you'd prefer:
GET /click/1.0/reviews/?lang=en&package_name=com.ubuntu.developer.dholbach.webapp-bvg
(url-encoded)

The original reason that the existing API uses the former
non-query-param filters is because not all caches will reliably cache
uri's with query params, but perhaps that's not so important (or
relevant) now (I'm not a squid expert). The flexibility of the second
option is certainly nicer (and more standard). We can move other
features (moderation, +1's etc.) across easily as we need them too.

As an aside, I mentioned to beuno today that I'm pretty sure we'll
also want to update the search.apps.u.c search results to include the
review stats (at the least, the current rating for each app in the
results so the client can display the stars, and only request reviews
when needed).

Cheers,
Michael

Revision history for this message
dobey (dobey) wrote :

I don't think we should spend time to build a slightly different API which does basically the same as passing "click" as the distroseries for everything.

Revision history for this message
dobey (dobey) :
review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/Makefile.am'
--- src/Makefile.am 2013-12-18 19:19:12 +0000
+++ src/Makefile.am 2014-01-09 13:55:57 +0000
@@ -44,7 +44,8 @@
44 click-interface.vala \44 click-interface.vala \
45 ubuntuone-credentials.vala \45 ubuntuone-credentials.vala \
46 non-click-scope.vala \46 non-click-scope.vala \
47 utils.vala47 utils.vala \
48 rnrclient.vala
4849
49config.vala: config.vala.in50config.vala: config.vala.in
50 sed -e "s|\@DATADIR\@|${datadir}|g" \51 sed -e "s|\@DATADIR\@|${datadir}|g" \
5152
=== modified file 'src/click-scope.vala'
--- src/click-scope.vala 2013-12-24 00:33:07 +0000
+++ src/click-scope.vala 2014-01-09 13:55:57 +0000
@@ -82,6 +82,7 @@
82 public ClickInterface click_if = new ClickInterface ();82 public ClickInterface click_if = new ClickInterface ();
83 public UbuntuoneCredentials u1creds = new UbuntuoneCredentials ();83 public UbuntuoneCredentials u1creds = new UbuntuoneCredentials ();
84 public ClickWebservice webservice = new ClickWebservice ();84 public ClickWebservice webservice = new ClickWebservice ();
85 RNRClient rnrClient = new RNRClient();
8586
86 public ClickScope ()87 public ClickScope ()
87 {88 {
@@ -123,7 +124,12 @@
123 preview.add_info(new Unity.InfoHint.with_variant(HINT_PUBLISHER, "Publisher", null, new Variant.string(details.publisher)));124 preview.add_info(new Unity.InfoHint.with_variant(HINT_PUBLISHER, "Publisher", null, new Variant.string(details.publisher)));
124 preview.add_info(new Unity.InfoHint.with_variant(HINT_SCREENSHOTS, LABEL_SCREENSHOTS, null, new Variant.strv(details.more_screenshot_urls)));125 preview.add_info(new Unity.InfoHint.with_variant(HINT_SCREENSHOTS, LABEL_SCREENSHOTS, null, new Variant.strv(details.more_screenshot_urls)));
125 preview.add_info(new Unity.InfoHint.with_variant(HINT_KEYWORDS, LABEL_KEYWORDS, null, new Variant.strv(details.keywords)));126 preview.add_info(new Unity.InfoHint.with_variant(HINT_KEYWORDS, LABEL_KEYWORDS, null, new Variant.strv(details.keywords)));
126 // TODO: get the proper ratings and reviews from the rnr web service127 // get the proper ratings and reviews from the rnr web service
128 var reviews = yield rnrClient.get_reviews(details);
129 if (reviews != null) {
130 preview.add_info(new Unity.InfoHint.with_variant(HINT_REVIEWS, LABEL_REVIEWS, null, reviews));
131 debug("Got %d reviews for %s", (int)reviews.n_children(), details.package_name);
132 }
127 return preview;133 return preview;
128 } catch (WebserviceError e) {134 } catch (WebserviceError e) {
129 debug ("Error calling webservice: %s", e.message);135 debug ("Error calling webservice: %s", e.message);
130136
=== modified file 'src/click-webservice.vala'
--- src/click-webservice.vala 2013-12-19 18:19:27 +0000
+++ src/click-webservice.vala 2014-01-09 13:55:57 +0000
@@ -32,6 +32,8 @@
32const string JSON_FIELD_SCREENSHOT_URLS = "screenshot_urls";32const string JSON_FIELD_SCREENSHOT_URLS = "screenshot_urls";
33const string JSON_FIELD_DESCRIPTION = "description";33const string JSON_FIELD_DESCRIPTION = "description";
34const string JSON_FIELD_KEYWORDS = "keywords";34const string JSON_FIELD_KEYWORDS = "keywords";
35const string JSON_FIELD_VERSION = "version";
36const string JSON_FIELD_FRAMEWORK = "framework";
3537
36// The size of the cache for click app data38// The size of the cache for click app data
37// == SIZE_IN_MB * 1024 * 102439// == SIZE_IN_MB * 1024 * 1024
@@ -117,6 +119,8 @@
117 public string main_screenshot_url { get; construct; }119 public string main_screenshot_url { get; construct; }
118 public string[] more_screenshot_urls { get; construct; }120 public string[] more_screenshot_urls { get; construct; }
119 public uint64 binary_filesize { get; construct; }121 public uint64 binary_filesize { get; construct; }
122 public string version { get; construct; }
123 public string[] framework { get; construct; }
120124
121125
122 /* TODO: use RnR webservice126 /* TODO: use RnR webservice
@@ -164,7 +168,9 @@
164168
165 title: details.get_string_member(JSON_FIELD_TITLE),169 title: details.get_string_member(JSON_FIELD_TITLE),
166 description: details.get_string_member(JSON_FIELD_DESCRIPTION),170 description: details.get_string_member(JSON_FIELD_DESCRIPTION),
167 keywords: parse_string_list (details, JSON_FIELD_KEYWORDS)171 keywords: parse_string_list (details, JSON_FIELD_KEYWORDS),
172 version: details.get_string_member(JSON_FIELD_VERSION),
173 framework: parse_string_list (details, JSON_FIELD_FRAMEWORK)
168 );174 );
169 }175 }
170}176}
171177
=== modified file 'src/fake-data.vala'
--- src/fake-data.vala 2013-08-08 19:25:09 +0000
+++ src/fake-data.vala 2014-01-09 13:55:57 +0000
@@ -88,3 +88,46 @@
88 }88 }
89]89]
90""";90""";
91
92const string FAKE_RNR_REVIEW_RESULTS = """
93[
94 {
95 "origin": "canonical",
96 "rating": 1,
97 "hide": false,
98 "app_name": "",
99 "language": "en",
100 "reviewer_username": "gbtest",
101 "usefulness_total": 31,
102 "usefulness_favorable": 30,
103 "review_text": "Cause system hangs a lot",
104 "date_deleted": null,
105 "summary": "poor linux version",
106 "version": "4.2.0.11-0ubuntu0.12.04.2",
107 "id": 7678621,
108 "date_created": "2013-08-11 13:23:13",
109 "reviewer_displayname": "Brian Test",
110 "package_name": "skyter",
111 "distroseries": "precise"
112 },
113 {
114 "origin": "canonical",
115 "rating": 4,
116 "hide": false,
117 "app_name": "",
118 "language": "en",
119 "reviewer_username": "user3844",
120 "usefulness_total": 6,
121 "usefulness_favorable": 6,
122 "review_text": "Great app versions",
123 "date_deleted": null,
124 "summary": "works stable, but has a bad interface",
125 "version": "4.2.0.11-0ubuntu0.12.04.2",
126 "id": 78054,
127 "date_created": "2013-09-09 18:59:20",
128 "reviewer_displayname": "Oron Pista",
129 "package_name": "skyter",
130 "distroseries": "raring"
131 }
132]
133""";
91134
=== added file 'src/rnrclient.vala'
--- src/rnrclient.vala 1970-01-01 00:00:00 +0000
+++ src/rnrclient.vala 2014-01-09 13:55:57 +0000
@@ -0,0 +1,201 @@
1/* -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
2/*
3 * Copyright (C) 2013-2014 Canonical, Ltd.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18using Json;
19
20/**
21 * RNRClient:
22 *
23 * Client for the ratings and reviews server.
24 * It is able to change the server address by setting the environment
25 * variable "U1_REVIEWS_BASE_URL".
26 *
27 */
28public class RNRClient : GLib.Object
29{
30 UbuntuoneCredentials u1creds;
31 const string CONSUMER_KEY = "consumer_key";
32 const string CONSUMER_SECRET = "consumer_secret";
33 const string TOKEN = "token";
34 const string TOKEN_SECRET = "token_secret";
35 const string REVIEWS_BASE_URL = "https://reviews.ubuntu.com/reviews";
36
37 internal Soup.SessionAsync http_session;
38
39 construct {
40 http_session = WebClient.get_webclient();
41 u1creds = new UbuntuoneCredentials ();
42 }
43
44 public string from_environ (string env_name, string default_value) {
45 string env_value = Environment.get_variable (env_name);
46 return env_value != null ? env_value : default_value;
47 }
48
49 public string get_base_url () {
50 return from_environ ("U1_REVIEWS_BASE_URL", REVIEWS_BASE_URL);
51 }
52
53 public string get_review_url() {
54 /* /api/1.0/reviews/filter/{LANGUAGE}/{ORIGIN}/{DISTROSERIES}/{VERSION}/{PACKAGENAME}/ */
55 return get_base_url() + "/api/1.0/reviews/filter/%s/%s/%s/%s/%s/";
56 }
57
58 /**
59 * get_reviews:
60 * @details: the AppDetails describe the details.
61 *
62 * The function returns all the reviews based on the application
63 * details. It only returns the reviews that matches the system
64 * language.
65 *
66 * Returns: A Variant (list of dictionary) that containts the reviews.
67 *
68 */
69 public async Variant? get_reviews(AppDetails details) {
70 string[] languages = GLib.Intl.get_language_names();
71 string? language = null;
72 if (languages.length > 0) {
73 language = languages[0];
74 }
75 var filter = new ReviewFilter();
76 filter.language = language;
77 filter.packagename = details.package_name;
78 filter.origin = filter.packagename;
79 filter.version = details.version;
80 filter.distroseries = "click";
81 return yield get_reviews_by_filter(filter);
82 }
83
84 /**
85 * get_reviews_by_filter:
86 * @filter: the filter for reviews.
87 *
88 * The function returns all the reviews based on the filter.
89 *
90 * Returns: A Variant (list of dictionary) that containts the reviews.
91 *
92 */
93 public async Variant? get_reviews_by_filter(ReviewFilter filter) {
94 Variant? ret = null;
95 WebserviceError failure = null;
96
97 if (filter.language == "" || filter.language == "any"
98 || filter.origin == "" || filter.origin == "any"
99 || filter.distroseries == "" || filter.distroseries == "any"
100 || filter.version == "" || filter.version == "any"
101 || filter.packagename == "") {
102 debug("filter is not filled");
103 return ret;
104 }
105
106 string url = get_review_url().printf(filter.language,
107 filter.origin,
108 filter.distroseries,
109 filter.version,
110 filter.packagename);
111 string response="";
112
113 var message = new Soup.Message ("GET", url);
114 http_session.queue_message(message, (http_session, message) => {
115 if (message.status_code != Soup.KnownStatusCode.OK) {
116 var msg = "Web request failed: HTTP %u %s".printf(
117 message.status_code, message.reason_phrase);
118 failure = new WebserviceError.HTTP_ERROR(msg);
119 } else {
120 message.response_body.flatten ();
121 response = (string) message.response_body.data;
122 debug ("response is %s", response);
123 }
124 get_reviews_by_filter.callback();
125 });
126 yield;
127 if (failure != null) {
128 debug("cannot get reviews error %s", failure.message);
129 return ret;
130 }
131 var parser = new Json.Parser();
132 try {
133 parser.load_from_data(response);
134 } catch (GLib.Error e) {
135 debug ("parse reviews response error %s", e.message);
136 return ret;
137 }
138
139 ret = convertJSONtoVariant(parser);
140 return ret;
141 }
142
143 public Variant? convertJSONtoVariant(Json.Parser parser) {
144 Variant? ret = null;
145 var root_object = parser.get_root();
146 var builder = new VariantBuilder(new VariantType("av"));
147
148 foreach (var node in root_object.get_array().get_elements()) {
149 var ht = new VariantBuilder(new VariantType("a{sv}"));
150 var node_object = node.get_object();
151 foreach (var node_member in node_object.get_members()) {
152 Variant? gvar_member = null;
153 try {
154 gvar_member = Json.gvariant_deserialize(node_object.get_member(node_member), null);
155 } catch (GLib.Error e) {
156 debug ("gvariant deserialize error: %s",e.message);
157 continue;
158 }
159 if (gvar_member == null) {
160 continue;
161 }
162 if (gvar_member.is_of_type(VariantType.MAYBE) && gvar_member.get_maybe() == null) {
163 continue;
164 }
165 ht.add("{sv}", node_member, gvar_member);
166 }
167 Variant dict = ht.end();
168 builder.add("v", dict);
169 }
170
171 ret = builder.end();
172 return ret;
173 }
174}
175
176/**
177 * ReviewFilter:
178 * @packagename: the name of package. Required.
179 * @language: the language string. Eg: en zh ... The default value "any" to
180 * get reviews for any languages
181 * @origin: Normally comes from "ubuntu". For click packages it should be
182 * as same as packagename.
183 * The default value "any" to get reviews for any origin.
184 * @distroseries: For example, "natty", "saucy". The default value "any" to
185 * get any distroseries.
186 * @version: The version of the software. Default value "any" means to get
187 * all versions from the server.
188 *
189 * ReviewFilter is the class used to pass the reviews filter to the server
190 * API to get the reviews. The server contains many reviews with different
191 * languages, different versions, etc. We should use the filter to get the
192 * reviews we want.
193 *
194 */
195public class ReviewFilter : GLib.Object {
196 public string packagename = "";
197 public string language = "any";
198 public string origin = "any";
199 public string distroseries = "any";
200 public string version = "any";
201}
0202
=== modified file 'src/test-click-webservice.vala'
--- src/test-click-webservice.vala 2013-12-24 00:33:07 +0000
+++ src/test-click-webservice.vala 2014-01-09 13:55:57 +0000
@@ -601,6 +601,50 @@
601 assert (scope.build_installed_called == (!is_installable && !finds_progress));601 assert (scope.build_installed_called == (!is_installable && !finds_progress));
602 }602 }
603603
604 public static void test_rnrclient_json_to_variant() {
605 RNRClient rnrClient = new RNRClient();
606 var testData1 = FAKE_RNR_REVIEW_RESULTS;
607 Json.Parser parser = new Json.Parser();
608 try {
609 parser.load_from_data(testData1);
610 } catch (GLib.Error e) {
611 }
612 Variant testVariant = rnrClient.convertJSONtoVariant(parser);
613
614 assert_cmpint ((int)testVariant.n_children(), OperatorType.EQUAL, 2);
615 }
616
617 public static void test_rnrclient_bad_filter() {
618 MainLoop mainloop = new MainLoop ();
619 RNRClient rnrClient = new RNRClient();
620
621 ReviewFilter filter = new ReviewFilter();
622 filter.version = "any";
623 Variant? testData1 = null;
624 rnrClient.get_reviews_by_filter.begin(filter, (obj, res) => {
625 mainloop.quit();
626 testData1 = rnrClient.get_reviews_by_filter.end (res);
627 });
628 assert (run_with_timeout (mainloop, 10000));
629 assert (testData1 == null);
630 }
631
632 public static void test_rnrclient_from_environ() {
633 RNRClient rnrClient = new RNRClient();
634
635 string testEnv = "TEST_RNRCLIENT_FROM_ENVIRON_S";
636 string defaultValue = "default";
637 string nonDefaultValue = "nondefault";
638
639 Environment.set_variable(testEnv, nonDefaultValue, true);
640 string test1 = rnrClient.from_environ(testEnv, defaultValue);
641 Environment.unset_variable(testEnv);
642 string test2 = rnrClient.from_environ(testEnv, defaultValue);
643
644 assert_cmpstr (test1, OperatorType.EQUAL, nonDefaultValue);
645 assert_cmpstr (test2, OperatorType.EQUAL, defaultValue);
646 }
647
604 public static int main (string[] args)648 public static int main (string[] args)
605 {649 {
606 Test.init (ref args);650 Test.init (ref args);
@@ -631,6 +675,9 @@
631 test_scope_build_default_preview_finds_progress_is_installable);675 test_scope_build_default_preview_finds_progress_is_installable);
632 Test.add_data_func ("/Unit/ClickChecker/Test_Scope_Build_Default_Preview_Finds_Progress_Not_Installable",676 Test.add_data_func ("/Unit/ClickChecker/Test_Scope_Build_Default_Preview_Finds_Progress_Not_Installable",
633 test_scope_build_default_preview_finds_progress_not_installable);677 test_scope_build_default_preview_finds_progress_not_installable);
678 Test.add_data_func ("/Unit/ClickChecker/Test_RNRClient_JSON_to_Variant", test_rnrclient_json_to_variant);
679 Test.add_data_func ("/Unit/ClickChecker/Test_RNRClient_Bad_Filter", test_rnrclient_bad_filter);
680 Test.add_data_func ("/Unit/ClickChecker/Test_RNRClient_From_Environ", test_rnrclient_from_environ);
634 return Test.run ();681 return Test.run ();
635 }682 }
636}683}

Subscribers

People subscribed via source and target branches

to all changes: