Merge lp:~benji/launchpad/bug-768336 into lp:launchpad

Proposed by Benji York
Status: Merged
Approved by: Brad Crittenden
Approved revision: no longer in the source branch.
Merged at revision: 12913
Proposed branch: lp:~benji/launchpad/bug-768336
Merge into: lp:launchpad
Diff against target: 135 lines (+26/-34)
3 files modified
lib/lp/bugs/javascript/bugtask_index_portlets.js (+14/-8)
lib/lp/bugs/javascript/subscriber.js (+12/-7)
lib/lp/bugs/javascript/tests/test_subscriber.js (+0/-19)
To merge this branch: bzr merge lp:~benji/launchpad/bug-768336
Reviewer Review Type Date Requested Status
Brad Crittenden (community) code Approve
Review via email: mp+58830@code.launchpad.net

Commit message

[r=bac][bug=768336][no-qa] fix subscriber name race condition

Description of the change

Bug 768336 describes a problem when subscribing to a bug: "on FF4, the
added row in the portlet only contains the person icon and the remove
icon, without my display name."

It turns out that there is a race condition when looking up a
subscriber's information via the web service. The request is dispatched
asynchronously, but the caller expects the results to be available when
the request-dispatching function returns; it often is not.

It looked like I was going to have to refactor the entire call chain to
be asynchronous, but there were two places where functions were called
without needing to return a result and they could be used as the points
to splice in asynchronous behavior without being hacky.

I can no longer reproduce the bug in FF4 and Chrome continues to work.

The existing tests continue to pass, they can be run by loading
lib/lp/bugs/javascript/tests/test_subscriber.html in a browser.

I made a small, related change by removing the unused displaynameload
event and associated test.

This branch is lint-free.

To post a comment you must log in.
Revision history for this message
Brad Crittenden (bac) wrote :

Nice branch Benji. Thanks for removing 'displaynameload' ... that's the sort of thing that could've lived for a long time doing absolutely nothing.

The rest of the branch looks good.

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/bugs/javascript/bugtask_index_portlets.js'
2--- lib/lp/bugs/javascript/bugtask_index_portlets.js 2011-04-22 11:23:48 +0000
3+++ lib/lp/bugs/javascript/bugtask_index_portlets.js 2011-04-22 18:19:47 +0000
4@@ -498,6 +498,14 @@
5 * @method add_user_name_link
6 */
7 function add_user_name_link(subscription) {
8+ // Be paranoid about display_name, since timeouts or other errors
9+ // could mean display_name wasn't set on initialization.
10+ subscription.get('person').set_display_name(function () {
11+ _add_user_name_link(subscription);
12+ });
13+}
14+
15+function _add_user_name_link(subscription) {
16 var person = subscription.get('person');
17 var link_node = build_user_link_html(subscription);
18 var subscribers = Y.one('#subscribers-links');
19@@ -982,11 +990,6 @@
20 var name = subscription.get('person').get('name');
21 var css_name = subscription.get('person').get('css_name');
22 var full_name = subscription.get('person').get('full_display_name');
23- // Be paranoid about display_name, since timeouts or other errors
24- // could mean display_name wasn't set on initialization.
25- if (subscription.get('person').get('display_name') === '') {
26- subscription.get('person').set_display_name();
27- }
28 var display_name = subscription.get('person').get('display_name');
29 var terms = {
30 name: name,
31@@ -1453,9 +1456,12 @@
32 function add_temp_user_name(subscription) {
33 // Be paranoid about display_name, since timeouts or other errors
34 // could mean display_name wasn't set on initialization.
35- if (subscription.get('person').get('display_name') === '') {
36- subscription.get('person').set_display_name();
37- }
38+ subscription.get('person').set_display_name(function () {
39+ _add_temp_user_name(subscription);
40+ });
41+}
42+
43+function _add_temp_user_name(subscription) {
44 var display_name = subscription.get('person').get('display_name');
45 var img_src;
46 if (subscription.is_team()) {
47
48=== modified file 'lib/lp/bugs/javascript/subscriber.js'
49--- lib/lp/bugs/javascript/subscriber.js 2011-04-19 18:03:50 +0000
50+++ lib/lp/bugs/javascript/subscriber.js 2011-04-22 18:19:47 +0000
51@@ -294,16 +294,20 @@
52 *
53 * @method get_display_name_from_api
54 * @param client {Object} An LP API client.
55+ * @param on_done {Object} A function to call when the display name has
56+ * been loaded.
57 */
58- get_display_name_from_api: function(client) {
59+ get_display_name_from_api: function(client, on_done) {
60 var self = this;
61 var cfg = {
62 on: {
63 success: function(person) {
64- self.set(
65- 'display_name', person.lookup_value('display_name'));
66+ var display_name = person.lookup_value('display_name');
67+ self.set('display_name', display_name);
68 self.set_truncated_display_name();
69- self.fire('displaynameload');
70+ if (Y.Lang.isFunction(on_done)) {
71+ on_done();
72+ }
73 }
74 }
75 };
76@@ -343,18 +347,19 @@
77 * correctly.
78 *
79 * @method set_display_name
80+ * @param on_done {Object} A function to call when the display name has
81+ * been loaded.
82 */
83- set_display_name: function() {
84+ set_display_name: function(on_done) {
85 var display_name = this.get_display_name_from_node();
86 if (display_name !== '') {
87 this.set('display_name', display_name);
88 this.set_truncated_display_name();
89- this.fire('displaynameload');
90 } else {
91 if (window.LP !== undefined &&
92 window.LP.links.me !== undefined) {
93 var client = new Y.lp.client.Launchpad();
94- this.get_display_name_from_api(client);
95+ this.get_display_name_from_api(client, on_done);
96 }
97 }
98 },
99
100=== modified file 'lib/lp/bugs/javascript/tests/test_subscriber.js'
101--- lib/lp/bugs/javascript/tests/test_subscriber.js 2011-04-19 18:03:50 +0000
102+++ lib/lp/bugs/javascript/tests/test_subscriber.js 2011-04-22 18:19:47 +0000
103@@ -157,7 +157,6 @@
104 get_display_name_from_api: function(client) {
105 this.set('display_name', 'From API');
106 this.set_truncated_display_name();
107- this.fire('displaynameload');
108 }
109 });
110
111@@ -202,24 +201,6 @@
112 }));
113
114 /*
115- * Test that the displaynameload event fires.
116- */
117-suite.add(new Y.Test.Case({
118- name: 'Subscriber displaynameload',
119-
120- test_display_name_load_event: function() {
121- var test = this;
122- var event_fired = false;
123- var subscriber = new Y.lp.bugs.subscriber.Subscriber();
124- subscriber.on('displaynameload', function(e) {
125- Y.assert(true);
126- });
127- subscriber.set('uri', '/~tester');
128- subscriber.initializer();
129- }
130-}));
131-
132-/*
133 * Test that a Subscription is properly initialized from
134 * a simple config and that the basic methods work.
135 */