Merge lp:~frankban/launchpad/bug-996720 into lp:launchpad

Proposed by Francesco Banconi on 2012-05-31
Status: Merged
Approved by: j.c.sackett on 2012-05-31
Approved revision: no longer in the source branch.
Merged at revision: 15345
Proposed branch: lp:~frankban/launchpad/bug-996720
Merge into: lp:launchpad
Diff against target: 219 lines (+82/-64)
2 files modified
lib/lp/soyuz/javascript/lp_dynamic_dom_updater.js (+35/-25)
lib/lp/soyuz/javascript/tests/lp_dynamic_dom_updater.js (+47/-39)
To merge this branch: bzr merge lp:~frankban/launchpad/bug-996720
Reviewer Review Type Date Requested Status
j.c.sackett (community) 2012-05-31 Approve on 2012-05-31
Review via email: mp+108196@code.launchpad.net

Commit Message

The bug: lib/lp/soyuz/javascript/tests/test_lp_dynamic_dom_updater.html fails rarely/intermittently in parallel tests.

Description of the Change

= Summary =

lib/lp/soyuz/javascript/tests/test_lp_dynamic_dom_updater.html fails rarely/intermittently in parallel tests.
This doesn't seem a test ordering or isolation issue, and it's not possible to reproduce the failure using the worker list attached to the bug. This seems to be a timing issue produced when the test is run in a heavy loaded machine, like the ec2 instances we use in parallel tests.

== Proposed fix ==

Many of the tests in lib/lp/soyuz/javascript/tests/lp_dynamic_dom_updater.js assume the test runner to be fast, and the environment to be responsive. We should either change the code to be able to mock times, or create a separate/testable function that handles polling intervals.

== Pre-implementation notes ==

Benji gave me a hint about the direction to follow.

== Implementation details ==

lib/lp/soyuz/javascript/lp_dynamic_dom_updater.js
Created a separate function that updates the polling interval, given the elapsed time.

lib/lp/soyuz/javascript/tests/lp_dynamic_dom_updater.js
The new function is now directly tested, and we can pass arbitrary elapsed times without having to mock _request_start.
s/constants/parameters in all the relevant tests.

== Tests ==

$ xvfb-run bin/test -cvvt lib/lp/soyuz/javascript/tests/test_lp_dynamic_dom_updater.html

== Demo and Q/A ==

no qa

To post a comment you must log in.
j.c.sackett (jcsackett) wrote :

This looks fine to land.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/soyuz/javascript/lp_dynamic_dom_updater.js'
2--- lib/lp/soyuz/javascript/lp_dynamic_dom_updater.js 2011-04-06 00:35:12 +0000
3+++ lib/lp/soyuz/javascript/lp_dynamic_dom_updater.js 2012-05-31 16:12:34 +0000
4@@ -282,6 +282,38 @@
5 },
6
7 /**
8+ * Update our actual poll interval depending on the elapsed time
9+ * for this request.
10+ *
11+ * @method _updateActualInterval
12+ * @private
13+ */
14+ _updateActualInterval: function(elapsed_time) {
15+ if (elapsed_time > this.get('long_processing_time')) {
16+ this._actual_interval *= 2;
17+ return true;
18+ }
19+ if (elapsed_time < this.get('short_processing_time')) {
20+ var new_actual_interval = this._actual_interval / 2;
21+
22+ // If the newly-calculated actual interval is greater than
23+ // the config interval then we update to the new interval,
24+ // otherwise if the actual interval is currently greater
25+ // than the config interval, then we update to the config
26+ // interval.
27+ var config_interval = this.get('interval');
28+ if (new_actual_interval >= config_interval) {
29+ this._actual_interval = new_actual_interval;
30+ return true;
31+ } else if (this._actual_interval > config_interval){
32+ this._actual_interval = config_interval;
33+ return true;
34+ }
35+ }
36+ return false;
37+ },
38+
39+ /**
40 * Success handler for the call to the LP API.
41 *
42 * @method _handleSuccess
43@@ -301,30 +333,9 @@
44 // subtree with the returned data.
45 this.update(data);
46
47- // Update our actual poll interval depending on the elapsed time
48- // for this request:
49- var actual_interval_updated = false;
50- if (elapsed_time > this.get('long_processing_time')) {
51- this._actual_interval *= 2;
52- actual_interval_updated = true;
53- } else if (elapsed_time < this.get('short_processing_time')) {
54- var new_actual_interval = this._actual_interval / 2;
55-
56- // If the newly-calculated actual interval is greater than
57- // the config interval then we update to the new interval,
58- // otherwise if the actual interval is currently greater
59- // than the config interval, then we update to the config
60- // interval.
61- var config_interval = this.get('interval');
62- if (new_actual_interval >= config_interval) {
63- this._actual_interval = new_actual_interval;
64- actual_interval_updated = true;
65- } else if (this._actual_interval > config_interval){
66- this._actual_interval = config_interval;
67- actual_interval_updated = true;
68- }
69- }
70-
71+ // Update our actual poll interval.
72+ var actual_interval_updated = this._updateActualInterval(
73+ elapsed_time)
74 if (actual_interval_updated) {
75 Y.log("Actual poll interval updated to " +
76 this._actual_interval + "ms.");
77@@ -334,7 +345,6 @@
78 setTimeout(
79 Y.bind(this.dynamicUpdate, this),
80 this._actual_interval);
81-
82 },
83
84 /**
85
86=== modified file 'lib/lp/soyuz/javascript/tests/lp_dynamic_dom_updater.js'
87--- lib/lp/soyuz/javascript/tests/lp_dynamic_dom_updater.js 2011-06-15 21:23:28 +0000
88+++ lib/lp/soyuz/javascript/tests/lp_dynamic_dom_updater.js 2012-05-31 16:12:34 +0000
89@@ -163,15 +163,17 @@
90 // Wait 5ms just to ensure that the DynamicDomUpdater finishes
91 // its initialization.
92 this.wait(function() {
93- // Before calling the success handler, ensure that the
94- // elapsed time will be evaluated as greater than the
95- // long_processing_time defined in the config.
96- this.eg_div.updater._request_start = new Date().getTime() - 11;
97- this.eg_div.updater._handleSuccess({msg: "Boo. I've changed."});
98+ var updated = this.eg_div.updater._updateActualInterval(
99+ this.config.long_processing_time + 1);
100+
101+ // The actual interval is updated.
102+ Assert.isTrue(
103+ updated,
104+ "Poll interval changed if request takes too long.");
105
106 // The actual interval should have doubled from 1ms to 2ms.
107 Assert.areEqual(
108- 2,
109+ this.config.interval * 2,
110 this.eg_div.updater._actual_interval,
111 "Poll interval doubled if request takes too long.");
112
113@@ -188,16 +190,18 @@
114 // Wait 5ms just to ensure that the DynamicDomUpdater finishes
115 // its initialization.
116 this.wait(function() {
117- // Before calling the success handler, ensure that the
118- // elapsed time will be evaluated as greater than the
119- // short_processing_time but less than the long_processing_time
120- // defined in the config.
121- this.eg_div.updater._request_start = new Date().getTime() - 7;
122- this.eg_div.updater._handleSuccess({msg: "Boo. I've changed."});
123+ var updated = this.eg_div.updater._updateActualInterval(
124+ (this.config.long_processing_time +
125+ this.config.short_processing_time) / 2);
126+
127+ // The actual interval is not updated.
128+ Assert.isFalse(
129+ updated,
130+ "Poll interval unchanged if request is timely.");
131
132 // The actual interval is unchanged.
133 Assert.areEqual(
134- 1,
135+ this.config.interval,
136 this.eg_div.updater._actual_interval,
137 "Poll interval unchanged if request is timely.");
138
139@@ -207,27 +211,28 @@
140 test_actual_interval_halved_if_request_is_quick: function() {
141 // The actual polling interval is halved if the elapsed time
142 // for the previous request was less than the short_processing_time
143-
144 this.eg_div.plug(
145 Y.lp.soyuz.dynamic_dom_updater.DynamicDomUpdater, this.config);
146
147 // Wait 5ms just to ensure that the DynamicDomUpdater finishes
148 // its initialization.
149 this.wait(function() {
150- // Before calling the success handler, ensure that the
151- // elapsed time will be evaluated as less than the
152- // short_processing_time defined in the config.
153- this.eg_div.updater._request_start = new Date().getTime();
154
155 // Ensure the current actual polling time is more than double the
156 // requested interval.
157- this.eg_div.updater._actual_interval = 16;
158-
159- this.eg_div.updater._handleSuccess({msg: "Boo. I've changed."});
160-
161- // The actual interval is unchanged.
162+ var actual_interval = this.config.interval * 4;
163+ this.eg_div.updater._actual_interval = actual_interval;
164+ var updated = this.eg_div.updater._updateActualInterval(
165+ this.config.short_processing_time - 1);
166+
167+ // The actual interval is updated.
168+ Assert.isTrue(
169+ updated,
170+ "Poll interval changed if request is faster than expected.");
171+
172+ // The actual interval is changed.
173 Assert.areEqual(
174- 8,
175+ actual_interval / 2,
176 this.eg_div.updater._actual_interval,
177 "Poll interval is halved if request is faster than " +
178 "expected.");
179@@ -245,23 +250,26 @@
180 // Wait 5ms just to ensure that the DynamicDomUpdater finishes
181 // its initialization.
182 this.wait(function() {
183- // Before calling the success handler, ensure that the
184- // elapsed time will be evaluated as less than the
185- // short_processing_time defined in the config.
186- this.eg_div.updater._request_start = new Date().getTime();
187-
188- // Ensure the current actual polling time is more than double the
189+ var interval = 10;
190+
191+ // Update the configuration interval:
192+ this.eg_div.updater.set('interval', interval);
193+
194+ // Ensure the current actual polling time is less than double the
195 // requested interval.
196- this.eg_div.updater._actual_interval = 16;
197-
198- // Ensure that the configuration interval is greater than 8:
199- this.eg_div.updater.set('interval', 10);
200-
201- this.eg_div.updater._handleSuccess({msg: "Boo. I've changed."});
202-
203- // The actual interval is unchanged.
204+ this.eg_div.updater._actual_interval = (interval * 2) - 2;
205+ var updated = this.eg_div.updater._updateActualInterval(
206+ this.config.short_processing_time - 1);
207+
208+ // The actual interval is updated.
209+ Assert.isTrue(
210+ updated,
211+ "Poll interval changed if request is faster than expected.");
212+
213+ // The actual interval is not smaller than the configuration
214+ // interval.
215 Assert.areEqual(
216- 10,
217+ interval,
218 this.eg_div.updater._actual_interval,
219 "Actual interval never goes below config interval.");
220