Merge lp:~kissiel/checkbox/rerun-in-cbt into lp:checkbox

Proposed by Maciej Kisielewski
Status: Merged
Approved by: Sylvain Pineau
Approved revision: 3917
Merged at revision: 3914
Proposed branch: lp:~kissiel/checkbox/rerun-in-cbt
Merge into: lp:checkbox
Diff against target: 323 lines (+168/-33)
6 files modified
checkbox-touch/checkbox-touch.qml (+34/-1)
checkbox-touch/components/CheckboxTouchApplication.qml (+6/-0)
checkbox-touch/components/SelectionPage.qml (+3/-1)
checkbox-touch/py/checkbox_touch.py (+22/-0)
checkbox-touch/tests/autopilot/checkbox_touch/__init__.py (+33/-0)
checkbox-touch/tests/autopilot/checkbox_touch/test_checkbox_touch.py (+70/-31)
To merge this branch: bzr merge lp:~kissiel/checkbox/rerun-in-cbt
Reviewer Review Type Date Requested Status
Sylvain Pineau (community) Approve
Review via email: mp+265232@code.launchpad.net

Description of the change

This MR brings re-run feature to checkbox-{touch|converged}

6e98004 chekcbox-touch: add function getting rerun candidates to py logic
d873a99 checkbox-touch: invalidate cache and reset index when tests are started
a7feee8 checkbox-touch: add proxy-ing to get rerun candidates in qml logic
214224d checkbox-touch: add emptyAllowed option to selection screen
e58246e checkbox-touch: add rerun screen
2db9319 checkbox-touch: run re-run before results screen
5d71b5b checkbox-touch:autopilot: move processing clicks helper to top-class
c0e491a checkbox-touch:autopilot: add generic check_results helper
7d49391 checkbox-touch:autopilot: add re-run scenarios for AP

To post a comment you must log in.
lp:~kissiel/checkbox/rerun-in-cbt updated
3905. By Zygmunt Krynicki

"automatic merge of lp:~zyga/checkbox/fix-1476136/ by tarmac [r=sylvain-pineau][bug=1476136][author=zyga]"

3906. By Maciej Kisielewski

"automatic merge of lp:~kissiel/checkbox/remove-lxml-from-cbt-reqs/ by tarmac [r=sylvain-pineau,zyga][bug=][author=kissiel]"

Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

When we landed the same feature for checkbox-cli, I thought that being unable to rerun every test would miss. But actually the only concern was about selection of all jobs dependencies (i.e suspend again if the test was depending on suspend_auto). So I agree with the decision to only select failed/crash test results.

Tests are presented with their respective categories which is great (clearly lacking in checkbox-gui).

So conclusion is a +1 for the design choices.

I ran the following sequence which was crashing the app:

- selected both sensor and screen categories from the qml provider
- failed one in each category
- rerun one succesfully
- killed cbt with a swipe move on the screen
- when prompted to resume the session selected rerun last test
- failed again the test "ensure haptics are working"
- at the final screen, select finish
- cbt controls are greyed out, app is blocked

The upstart log: http://pastebin.ubuntu.com/11918666/

review: Needs Fixing
lp:~kissiel/checkbox/rerun-in-cbt updated
3907. By Maciej Kisielewski

checkbox-touch: remember test_plan_id once it's selected

Signed-off-by: Maciej Kisielewski <email address hidden>

3908. By Maciej Kisielewski

checkbox-touch: make resuming re-initiate test-plan

Signed-off-by: Maciej Kisielewski <email address hidden>

3909. By Maciej Kisielewski

chekcbox-touch: add function getting rerun candidates to py logic

Signed-off-by: Maciej Kisielewski <email address hidden>

3910. By Maciej Kisielewski

checkbox-touch: invalidate cache and reset index when tests are started

Signed-off-by: Maciej Kisielewski <email address hidden>

3911. By Maciej Kisielewski

checkbox-touch: add proxy-ing to get rerun candidates in qml logic

Signed-off-by: Maciej Kisielewski <email address hidden>

3912. By Maciej Kisielewski

checkbox-touch: add emptyAllowed option to selection screen

This patch adds an option to SelectionPage component that lets user proceed
even if nothing is selected.

Signed-off-by: Maciej Kisielewski <email address hidden>

3913. By Maciej Kisielewski

checkbox-touch: add rerun screen

Signed-off-by: Maciej Kisielewski <email address hidden>

3914. By Maciej Kisielewski

checkbox-touch: run re-run before results screen

Signed-off-by: Maciej Kisielewski <email address hidden>

3915. By Maciej Kisielewski

checkbox-touch:autopilot: move processing clicks helper to top-class

This patch moves the helper that executes common scenario of clicking through
pages, to the ClickAppTestCase class, so all our test classes inherit this.

Signed-off-by: Maciej Kisielewski <email address hidden>

3916. By Maciej Kisielewski

checkbox-touch:autopilot: add generic check_results helper

This patch adds a helper function that checks if the result screen is shown
with the expected values.

Signed-off-by: Maciej Kisielewski <email address hidden>

3917. By Maciej Kisielewski

checkbox-touch:autopilot: add re-run scenarios for AP

Signed-off-by: Maciej Kisielewski <email address hidden>

Revision history for this message
Maciej Kisielewski (kissiel) wrote :

> When we landed the same feature for checkbox-cli, I thought that being unable
> to rerun every test would miss. But actually the only concern was about
> selection of all jobs dependencies (i.e suspend again if the test was
> depending on suspend_auto). So I agree with the decision to only select
> failed/crash test results.
>
> Tests are presented with their respective categories which is great (clearly
> lacking in checkbox-gui).
>
> So conclusion is a +1 for the design choices.
>
> I ran the following sequence which was crashing the app:
>
> - selected both sensor and screen categories from the qml provider
> - failed one in each category
> - rerun one succesfully
> - killed cbt with a swipe move on the screen
> - when prompted to resume the session selected rerun last test
> - failed again the test "ensure haptics are working"
> - at the final screen, select finish
> - cbt controls are greyed out, app is blocked
>
> The upstart log: http://pastebin.ubuntu.com/11918666/

Rerun + resume now works. Tested with your scenario, and the scenario when resume is done before any job is rerun.

Revision history for this message
Sylvain Pineau (sylvain-pineau) wrote :

Re tested, it works! Thanks

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'checkbox-touch/checkbox-touch.qml'
--- checkbox-touch/checkbox-touch.qml 2015-07-16 13:58:31 +0000
+++ checkbox-touch/checkbox-touch.qml 2015-07-23 08:26:16 +0000
@@ -357,6 +357,30 @@
357 }357 }
358 }358 }
359359
360 SelectionPage {
361 id: rerunSelectionPage
362 objectName: "rerunSelectionPage"
363 title: i18n.tr("Select tests to re-run")
364 continueText: state == "empty selection" ?
365 i18n.tr("Finish") : i18n.tr("Re-run")
366 emptyAllowed: true
367
368 function setup(rerunCandidates, continuation) {
369 model.clear();
370 for (var i=0; i<rerunCandidates.length; i++) {
371 model.append(rerunCandidates[i]);
372 }
373 modelUpdated();
374 pageStack.push(rerunSelectionPage)
375 }
376 onSelectionDone: {
377 app.rememberTestSelection(selected_id_list, function() {
378 processNextTest();
379 unlatchContinue();
380 });
381 }
382 }
383
360 PasswordDialog {384 PasswordDialog {
361 id: passwordDialog385 id: passwordDialog
362 }386 }
@@ -388,7 +412,7 @@
388 app.getNextTest(function(test) {412 app.getNextTest(function(test) {
389 pageStack.clear();413 pageStack.clear();
390 if (test.plugin === undefined) { 414 if (test.plugin === undefined) {
391 return showResultsScreen();415 return maybeShowRerunScreen();
392 }416 }
393 if (test.user) {417 if (test.user) {
394 // running this test will require to be run as a different418 // running this test will require to be run as a different
@@ -449,6 +473,15 @@
449 app.runTestActivity(test, continuation);473 app.runTestActivity(test, continuation);
450474
451 }475 }
476 function maybeShowRerunScreen() {
477 app.getRerunCandidates(function(result) {
478 if (result == false) {
479 showResultsScreen();
480 return;
481 }
482 rerunSelectionPage.setup(result);
483 });
484 }
452485
453 function showResultsScreen() {486 function showResultsScreen() {
454 pageStack.clear();487 pageStack.clear();
455488
=== modified file 'checkbox-touch/components/CheckboxTouchApplication.qml'
--- checkbox-touch/components/CheckboxTouchApplication.qml 2015-06-30 22:20:49 +0000
+++ checkbox-touch/components/CheckboxTouchApplication.qml 2015-07-23 08:26:16 +0000
@@ -138,6 +138,12 @@
138 });138 });
139 }139 }
140140
141 function getRerunCandidates(continuation) {
142 request("get_rerun_candidates", [], continuation, function(error) {
143 console.error("Unable to get rerun candidates");
144 });
145 }
146
141 function getResults(continuation) {147 function getResults(continuation) {
142 request("get_results", [], continuation, function(error) {148 request("get_results", [], continuation, function(error) {
143 console.error("Unable to get test results");149 console.error("Unable to get test results");
144150
=== modified file 'checkbox-touch/components/SelectionPage.qml'
--- checkbox-touch/components/SelectionPage.qml 2015-07-17 08:36:57 +0000
+++ checkbox-touch/components/SelectionPage.qml 2015-07-23 08:26:16 +0000
@@ -36,6 +36,7 @@
36 property string continueText: i18n.tr("Continue")36 property string continueText: i18n.tr("Continue")
37 readonly property alias model: selectionModel37 readonly property alias model: selectionModel
38 property bool onlyOneAllowed: false38 property bool onlyOneAllowed: false
39 property bool emptyAllowed: false
3940
40 visible: false41 visible: false
41 flickable: null42 flickable: null
@@ -100,7 +101,8 @@
100 states: [101 states: [
101 State {102 State {
102 name: "empty selection"103 name: "empty selection"
103 PropertyChanges { target: continueButton; enabled: false }104 PropertyChanges { target: continueButton;
105 enabled: false || emptyAllowed }
104 },106 },
105 State {107 State {
106 name: "nonempty selection"108 name: "nonempty selection"
107109
=== modified file 'checkbox-touch/py/checkbox_touch.py'
--- checkbox-touch/py/checkbox_touch.py 2015-07-16 21:25:01 +0000
+++ checkbox-touch/py/checkbox_touch.py 2015-07-23 08:26:16 +0000
@@ -248,6 +248,7 @@
248 self.context.provider_list,248 self.context.provider_list,
249 os.path.join(self.manager.storage.location, 'io-logs'))249 os.path.join(self.manager.storage.location, 'io-logs'))
250 self.index = app_blob['index_in_run_list']250 self.index = app_blob['index_in_run_list']
251 self._init_test_plan_id(app_blob['test_plan_id'])
251 _logger.error(self.context.state.run_list)252 _logger.error(self.context.state.run_list)
252 _logger.error(self.index)253 _logger.error(self.index)
253 if not rerun_last_test:254 if not rerun_last_test:
@@ -399,6 +400,24 @@
399 return {400 return {
400 'test_info_list': test_info_list401 'test_info_list': test_info_list
401 }402 }
403 @view
404 def get_rerun_candidates(self):
405 def rerun_predicate(job_state):
406 return job_state.result.outcome in (
407 IJobResult.OUTCOME_FAIL, IJobResult.OUTCOME_CRASH)
408 id_map = self.context.compute_shared(
409 'id_map', compute_value_map, self.context, 'id')
410 rerun_candidates = []
411 for job in self.manager.state.run_list:
412 if rerun_predicate(self.manager.state.job_state_map[job.id]):
413 rerun_candidates.append({
414 "mod_id": job.id,
415 "mod_name": job.tr_summary(),
416 "mod_group": id_map[job.category_id][0].tr_name(),
417 "mod_selected": False
418
419 })
420 return rerun_candidates
402421
403 @view422 @view
404 def remember_tests(self, selected_id_list):423 def remember_tests(self, selected_id_list):
@@ -407,6 +426,8 @@
407 """426 """
408 self.desired_test_ids = frozenset(selected_id_list)427 self.desired_test_ids = frozenset(selected_id_list)
409 _logger.info("Selected tests: %s", self.desired_test_ids)428 _logger.info("Selected tests: %s", self.desired_test_ids)
429 self.index = 0
430 self.context.invalidate_shared('desired_job_list')
410 desired_job_list = self.context.compute_shared(431 desired_job_list = self.context.compute_shared(
411 'desired_job_list', select_jobs,432 'desired_job_list', select_jobs,
412 self.context.state.job_list, [433 self.context.state.job_list, [
@@ -611,6 +632,7 @@
611 if test_plan.Meta.name != 'test plan':632 if test_plan.Meta.name != 'test plan':
612 raise ValueError(633 raise ValueError(
613 "unit {!r} is not a test plan".format(test_plan_id))634 "unit {!r} is not a test plan".format(test_plan_id))
635 self.test_plan_id = test_plan_id
614 self.test_plan = test_plan636 self.test_plan = test_plan
615637
616 def _init_session_storage_repo(self):638 def _init_session_storage_repo(self):
617639
=== modified file 'checkbox-touch/tests/autopilot/checkbox_touch/__init__.py'
--- checkbox-touch/tests/autopilot/checkbox_touch/__init__.py 2015-07-15 15:32:59 +0000
+++ checkbox-touch/tests/autopilot/checkbox_touch/__init__.py 2015-07-23 08:26:16 +0000
@@ -89,6 +89,39 @@
89 objectName='continueButton')89 objectName='continueButton')
90 self.pointing_device.click_object(continue_btn)90 self.pointing_device.click_object(continue_btn)
9191
92 def process_sequence_of_clicks_on_pages(self, steps):
93 """
94 Do a sequence of clicks on simple page->component hierarchies.
95
96 :param steps:
97 sequence of (page-objectName, component-objectName) pairs to go
98 through.
99
100 Typical run of checkbox-touch requires user to go through a sequence of
101 pages that have pass/fail buttons on them. This function helps go
102 through a sequence like that.
103 """
104 for parent, component in steps:
105 self.app.wait_select_single(
106 objectName=parent, visible=True)
107 clickable = self.main_view.wait_select_single(
108 objectName=component, visible=True)
109 self.pointing_device.click_object(clickable)
110
111 def check_results(self, results):
112 results_page = self.app.wait_select_single(
113 objectName='resultsPage', visible=True)
114 lbl_passed = results_page.wait_select_single(objectName='passedLabel')
115 self.assertThat(lbl_passed.text.startswith(results['passed']),
116 Equals(True))
117 lbl_failed = results_page.wait_select_single(objectName='failedLabel')
118 self.assertThat(lbl_failed.text.startswith(results['failed']),
119 Equals(True))
120 lbl_skipped = results_page.wait_select_single(
121 objectName='skippedLabel')
122 self.assertThat(lbl_skipped.text.startswith(results['skipped']),
123 Equals(True))
124
92 def launch_application(self):125 def launch_application(self):
93 if platform.model() == 'Desktop':126 if platform.model() == 'Desktop':
94 self._launch_application_from_desktop()127 self._launch_application_from_desktop()
95128
=== modified file 'checkbox-touch/tests/autopilot/checkbox_touch/test_checkbox_touch.py'
--- checkbox-touch/tests/autopilot/checkbox_touch/test_checkbox_touch.py 2015-07-15 15:32:57 +0000
+++ checkbox-touch/tests/autopilot/checkbox_touch/test_checkbox_touch.py 2015-07-23 08:26:16 +0000
@@ -23,25 +23,6 @@
23 yes_btn = dialog.select_single(objectName='yesButton')23 yes_btn = dialog.select_single(objectName='yesButton')
24 self.pointing_device.click_object(yes_btn)24 self.pointing_device.click_object(yes_btn)
2525
26 def process_sequence_of_clicks_on_pages(self, steps):
27 """
28 Do a sequence of clicks on simple page->component hierarchies.
29
30 :param steps:
31 sequence of (page-objectName, component-objectName) pairs to go
32 through.
33
34 Typical run of checkbox-touch requires user to go through a sequence of
35 pages that have pass/fail buttons on them. This function helps go
36 through a sequence like that.
37 """
38 for parent, component in steps:
39 self.app.wait_select_single(
40 objectName=parent, visible=True)
41 clickable = self.main_view.wait_select_single(
42 objectName=component, visible=True)
43 self.pointing_device.click_object(clickable)
44
45 def test_launches(self):26 def test_launches(self):
46 main_view = self.app.select_single(objectName='mainView')27 main_view = self.app.select_single(objectName='mainView')
47 self.assertThat(main_view.visible, Eventually(Equals(True)))28 self.assertThat(main_view.visible, Eventually(Equals(True)))
@@ -116,22 +97,12 @@
116 next_steps = [97 next_steps = [
117 ('qmlNativePage', 'continueButton'),98 ('qmlNativePage', 'continueButton'),
118 ('qmlTestPage', 'passButton'),99 ('qmlTestPage', 'passButton'),
100 ('rerunSelectionPage', 'continueButton')
119 ]101 ]
120 self.process_sequence_of_clicks_on_pages(next_steps)102 self.process_sequence_of_clicks_on_pages(next_steps)
121 # we should see results screen now103 # we should see results screen now
122 results_page = self.app.wait_select_single(
123 objectName='resultsPage', visible=True)
124 results = {'passed': '10', 'failed': '5', 'skipped': '5'}104 results = {'passed': '10', 'failed': '5', 'skipped': '5'}
125 lbl_passed = results_page.wait_select_single(objectName='passedLabel')105 self.check_results(results)
126 self.assertThat(lbl_passed.text.startswith(results['passed']),
127 Equals(True))
128 lbl_failed = results_page.wait_select_single(objectName='failedLabel')
129 self.assertThat(lbl_failed.text.startswith(results['failed']),
130 Equals(True))
131 lbl_skipped = results_page.wait_select_single(
132 objectName='skippedLabel')
133 self.assertThat(lbl_skipped.text.startswith(results['skipped']),
134 Equals(True))
135106
136107
137class SessionResumeTests(checkbox_touch.ClickAppTestCase):108class SessionResumeTests(checkbox_touch.ClickAppTestCase):
@@ -228,3 +199,71 @@
228 text_area = output_page.wait_select_single(199 text_area = output_page.wait_select_single(
229 objectName='textArea', visible=True)200 objectName='textArea', visible=True)
230 self.assertThat(text_area.text, Eventually(Equals("foobar\n")))201 self.assertThat(text_area.text, Eventually(Equals("foobar\n")))
202
203
204class RerunTests(checkbox_touch.ClickAppTestCase):
205 def test_rerun_after_rerun(self):
206 test_id = '2015.com.canonical.certification::autopilot/manual-2'
207 self.start_and_select_tests(
208 '2015.com.canonical.certification::normal', [test_id])
209 next_steps = [
210 ('manualIntroPage', 'continueButton'),
211 ('testVerificationPage', 'failButton'),
212 ]
213 self.process_sequence_of_clicks_on_pages(next_steps)
214 # we now should see a re-run screen; let's select the only test
215 rerun_page = self.app.wait_select_single(
216 objectName='rerunSelectionPage', visible=True)
217 list_item = rerun_page.wait_select_single(
218 objectName='listItem', item_mod_id=test_id)
219 self.pointing_device.click_object(list_item)
220 continue_btn = rerun_page.wait_select_single(
221 objectName='continueButton', visible=True)
222 self.pointing_device.click_object(continue_btn)
223 # run the same steps as before
224 self.process_sequence_of_clicks_on_pages(next_steps)
225 # we should see the re-run screen again
226 rerun_page = self.app.wait_select_single(
227 objectName='rerunSelectionPage', visible=True)
228 continue_btn = rerun_page.wait_select_single(
229 objectName='continueButton', visible=True)
230 self.pointing_device.click_object(continue_btn)
231 self.check_results({'passed': '0', 'failed': '1', 'skipped': '0'})
232
233 def test_rerun_after_fail(self):
234 test_id = '2015.com.canonical.certification::autopilot/manual-2'
235 self.start_and_select_tests(
236 '2015.com.canonical.certification::normal', [test_id])
237 next_steps = [
238 ('manualIntroPage', 'continueButton'),
239 ('testVerificationPage', 'failButton'),
240 ]
241 self.process_sequence_of_clicks_on_pages(next_steps)
242 # we now should see a re-run screen; let's select the only test
243 rerun_page = self.app.wait_select_single(
244 objectName='rerunSelectionPage', visible=True)
245 list_item = rerun_page.wait_select_single(
246 objectName='listItem', item_mod_id=test_id)
247 self.pointing_device.click_object(list_item)
248 continue_btn = rerun_page.wait_select_single(
249 objectName='continueButton', visible=True)
250 self.pointing_device.click_object(continue_btn)
251 next_steps = [
252 ('manualIntroPage', 'continueButton'),
253 ('testVerificationPage', 'passButton'),
254 ]
255 self.process_sequence_of_clicks_on_pages(next_steps)
256 # now set the outcome to 'pass'; we should be on results screen now
257 self.check_results({'passed': '1', 'failed': '0', 'skipped': '0'})
258
259 def test_no_rerun_after_pass(self):
260 test_id = '2015.com.canonical.certification::autopilot/manual-1'
261 self.start_and_select_tests(
262 '2015.com.canonical.certification::normal', [test_id])
263 next_steps = [
264 ('manualIntroPage', 'continueButton'),
265 ('testVerificationPage', 'passButton'),
266 ]
267 self.process_sequence_of_clicks_on_pages(next_steps)
268 # there should be no re-run screen, just results
269 self.check_results({'passed': '1', 'failed': '0', 'skipped': '0'})

Subscribers

People subscribed via source and target branches