~jocave/checkbox/hybrid-amd-gpu-mods

« back to all changes in this revision

Viewing changes to checkbox-touch/checkbox-touch.qml

  • Committer: Sylvain Pineau
  • Date: 2014-07-29 16:05:54 UTC
  • mto: This revision was merged to the branch mainline in revision 3149.
  • Revision ID: sylvain.pineau@canonical.com-20140729160554-qev8887xbunn9tmi
checkbox-ng:launchers:checkbox-cli: The checkbox-cli launcher

Running the default whitelist (with the suite selection screen skipped)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * This file is part of Checkbox
3
 
 *
4
 
 * Copyright 2014, 2015 Canonical Ltd.
5
 
 *
6
 
 * Authors:
7
 
 * - Zygmunt Krynicki <zygmunt.krynicki@canonical.com>
8
 
 * - Maciej Kisielewski <maciej.kisielewski@canonical.com>
9
 
 *
10
 
 * This program is free software; you can redistribute it and/or modify
11
 
 * it under the terms of the GNU General Public License as published by
12
 
 * the Free Software Foundation; version 3.
13
 
 *
14
 
 * This program is distributed in the hope that it will be useful,
15
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 
 * GNU General Public License for more details.
18
 
 *
19
 
 * You should have received a copy of the GNU General Public License
20
 
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 
 */
22
 
import QtQuick 2.0
23
 
import Ubuntu.Components 1.1
24
 
import Ubuntu.Components.Popups 0.1
25
 
import QtQuick.Layouts 1.1
26
 
import io.thp.pyotherside 1.4
27
 
import "components"
28
 
import "components/ErrorLogic.js" as ErrorLogic
29
 
import "components/CbtDialogLogic.js" as CbtDialogLogic
30
 
 
31
 
 
32
 
/*!
33
 
    \brief MainView with a Label and Button elements.
34
 
*/
35
 
 
36
 
MainView {
37
 
    id: mainView
38
 
 
39
 
    // objectName for functional testing purposes (autopilot-qt5)
40
 
    objectName: "mainView"
41
 
 
42
 
    // Note! applicationName needs to match the "name" field of the click manifest
43
 
    applicationName: "com.canonical.certification.checkbox-touch"
44
 
 
45
 
    /*
46
 
     This property enables the application to change orientation
47
 
     when the device is rotated. The default is false.
48
 
    */
49
 
    //automaticOrientation: true
50
 
 
51
 
    width: units.gu(100)
52
 
    height: units.gu(75)
53
 
 
54
 
    useDeprecatedToolbar: false
55
 
 
56
 
    // appSettings serves as application-wide storage for global variables
57
 
    // it has to have at least one entry to be constructed
58
 
    property var appSettings: {
59
 
        "applicationName" : applicationName,
60
 
        "revision": "unknown revision",
61
 
        "testplan": "",
62
 
        "providersDir": "providers",
63
 
        "submission": null
64
 
    }
65
 
 
66
 
    Arguments {
67
 
        id: args
68
 
        Argument {
69
 
            name: "autopilot"
70
 
            help: i18n.tr("Run Checkbox-Touch in autopilot-testing mode")
71
 
            required: false
72
 
        }
73
 
        Argument {
74
 
            name: "quiet"
75
 
            help: i18n.tr("Write only warnings and errors to standard error")
76
 
            required: false
77
 
        }
78
 
        Argument {
79
 
            name: "settings"
80
 
            valueNames: "PATH_TO_SETTINGS"
81
 
            help: i18n.tr("Path to a file containing checkbox-touch settings")
82
 
            required: true
83
 
        }
84
 
    }
85
 
 
86
 
    Component.onCompleted: {
87
 
        i18n.domain = "com.ubuntu.checkbox";
88
 
        if (args.values["autopilot"]) {
89
 
            // autopilot-testing mode
90
 
            appSettings["testplan"] = "2015.com.canonical.certification::checkbox-touch-autopilot";
91
 
            appSettings["providersDir"] = "tests/autopilot/autopilot-provider";
92
 
            appSettings["log-level"] = "warning";
93
 
        } else {
94
 
            // normal execution - load settings.json file
95
 
            var xhr = new XMLHttpRequest;
96
 
            xhr.open("GET", args.values["settings"]);
97
 
            xhr.onreadystatechange = function() {
98
 
                if (xhr.readyState == XMLHttpRequest.DONE) {
99
 
                    try {
100
 
                        var newAppSettings = JSON.parse(xhr.responseText);
101
 
                    } catch (x) {
102
 
                        // if we cannot parse settings.json, we should leave
103
 
                        // deafult values of appSettings
104
 
                        console.error("Could not parse settings.json. Using default values");
105
 
                    }
106
 
                    // overwrite/add appSettings' attributes that got loaded
107
 
                    for (var attr in newAppSettings) {
108
 
                        appSettings[attr] = newAppSettings[attr];
109
 
                    }
110
 
                }
111
 
            }
112
 
            xhr.send();
113
 
        }
114
 
        if (args.values["quiet"]) {
115
 
            // monkey-patch console.log and console.info to do nothing
116
 
            console.log = function() {};
117
 
            console.info = function() {};
118
 
            appSettings["log-level"] = "warning";
119
 
        }
120
 
        py.init()
121
 
    }
122
 
 
123
 
 
124
 
    // Pyotherside python object that we use to talk to all of plainbox
125
 
    Python {
126
 
        id: py
127
 
 
128
 
        function init() {
129
 
            console.log("Pyotherside version " + pluginVersion());
130
 
            console.log("Python version " + pythonVersion());
131
 
            // A bit hacky but that's where the python code is
132
 
            addImportPath(Qt.resolvedUrl('py/'));
133
 
            // Import path for plainbox and potentially other python libraries
134
 
            addImportPath(Qt.resolvedUrl('lib/py'))
135
 
            setHandler('command_output', commandOutputPage.addText);
136
 
            initiated();
137
 
        }
138
 
 
139
 
        // gets triggered when python object is ready to be used
140
 
        signal initiated
141
 
 
142
 
        onError: {
143
 
            console.error("python error: " + traceback);
144
 
            ErrorLogic.showError(mainView, "python error: " + traceback, Qt.quit);
145
 
        }
146
 
        onReceived: console.log("pyotherside.send: " + data)
147
 
    }
148
 
 
149
 
    // Component representing our application
150
 
    CheckboxTouchApplication {
151
 
        id: app
152
 
        py: py
153
 
        property var incompleteSessions: []
154
 
        onAppReady: {
155
 
            console.log("Plainbox version " + plainboxVersion);
156
 
            console.log("Checkbox Touch version " + applicationVersion);
157
 
            aboutPage.versionInfo = {
158
 
                "checkbox_touch" : applicationVersion,
159
 
                "plainbox" : plainboxVersion
160
 
            };
161
 
            getIncompleteSessions(function(sessions) {
162
 
                incompleteSessions = sessions;
163
 
                resumeSessionPage.incompleteSessionCount = sessions.length;
164
 
            });
165
 
            resumeOrStartSession();
166
 
        }
167
 
        onSessionReady: {
168
 
            welcomePage.enableButton()
169
 
        }
170
 
        Component.onCompleted: {
171
 
            // register to py.initiated signal
172
 
            py.onInitiated.connect(function() {
173
 
                construct("checkbox_touch.create_app_object", []);
174
 
            });
175
 
        }
176
 
    }
177
 
 
178
 
    PythonLogger {
179
 
        id: logger
180
 
        py: py
181
 
        Component.onCompleted: {
182
 
            // register to py.initiated signal
183
 
            py.onInitiated.connect(function() {
184
 
                py.importModule("checkbox_touch", function() {
185
 
                    construct("checkbox_touch.get_qml_logger",
186
 
                             [appSettings["log-level"] || "info"]);
187
 
                });
188
 
            });
189
 
        }
190
 
    }
191
 
 
192
 
    PageStack {
193
 
        id: pageStack
194
 
        Component.onCompleted: push(welcomePage)
195
 
    }
196
 
 
197
 
    WelcomePage {
198
 
        id: welcomePage
199
 
        // TRANSLATORS: %1 means program version, %2 repository revision and %3
200
 
        // date when the package was built
201
 
        // TRANSLATORS: keep the '\n' characters at the end of each line
202
 
        welcomeText: i18n.tr("Welcome to Checkbox Touch\nVersion: %1\n(%2 %3)")
203
 
            .arg(app.applicationVersion).arg(appSettings.revision).arg(appSettings.clickBuildDate)
204
 
        onStartTestingTriggered: {
205
 
            if (appSettings.testplan != "") {
206
 
                app.rememberTestplan(appSettings.testplan, function() {
207
 
                    categorySelectionPage.setup();
208
 
                    enableButton();
209
 
                });
210
 
            } else {
211
 
                app.getTestplans(function(response) {
212
 
                    var tp_list = response.testplan_info_list;
213
 
                    if (tp_list.length < 2 && tp_list.length > 0) {
214
 
                        app.rememberTestplan(tp_list[0].mod_id, function() {
215
 
                            categorySelectionPage.setup();
216
 
                        });
217
 
                    }
218
 
                    else {
219
 
                        testplanSelectionPage.setup(tp_list)
220
 
                    }
221
 
                    enableButton();
222
 
                });
223
 
            }
224
 
        }
225
 
        onAboutClicked: pageStack.push(aboutPage)
226
 
    }
227
 
 
228
 
    AboutPage {
229
 
        id: aboutPage
230
 
        visible: false
231
 
    }
232
 
 
233
 
    Item {
234
 
        id: progressHeader
235
 
        visible: false
236
 
        property alias progressText: _progressText.text
237
 
        property alias value: _progressBar.value
238
 
        property alias maximumValue: _progressBar.maximumValue
239
 
        ColumnLayout{
240
 
            anchors {
241
 
                fill: parent
242
 
                verticalCenter: parent.verticalCenter
243
 
                bottomMargin: units.gu(1.5)
244
 
                rightMargin: units.gu(1)
245
 
                // leftMargin should compensate for potential 'back' action that might appear on next page
246
 
                // so the whole progressHeader stays in the same spot on the screen throughout the session
247
 
                leftMargin:  pageStack.depth == 1 ? units.gu(5) : units.gu(1)
248
 
 
249
 
            }
250
 
            Label {
251
 
                text: pageStack.currentPage ? pageStack.currentPage.title : ""
252
 
                fontSize: "x-large"
253
 
                font.weight: Font.Light
254
 
                anchors.verticalCenter: parent.verticalCenter
255
 
            }
256
 
            Label {
257
 
                id: _progressText
258
 
                fontSize: "x-small"
259
 
                font.weight: Font.Light
260
 
                anchors.right: parent.right
261
 
                anchors.bottom: parent.bottom
262
 
            }
263
 
            ProgressBox {
264
 
                id: _progressBar
265
 
                value: 0
266
 
                maximumValue: 1
267
 
                implicitWidth: parent.width
268
 
            }
269
 
        }
270
 
 
271
 
        function update(test) {
272
 
            progressHeader.visible = true;
273
 
            progressHeader.progressText = Number(test.test_number / test.tests_count * 100.0).toFixed(0) + "% ("+test.test_number + "/" + test.tests_count + ")";
274
 
            progressHeader.value = test.test_number
275
 
            progressHeader.maximumValue = test.tests_count
276
 
        }
277
 
    }
278
 
 
279
 
    ResumeSessionPage {
280
 
        id: resumeSessionPage
281
 
        onRerunLast: app.resumeSession(true, processNextTest)
282
 
        onContinueSession: app.resumeSession(false, processNextTest)
283
 
        resumeText: i18n.tr("Checkbox session got suspended.\nDo you want \
284
 
 to rerun last test, continue to the next test, or start a new session?")
285
 
        onRestartSession: {
286
 
            pageStack.clear();
287
 
            pageStack.push(welcomePage);
288
 
            gcAndStartSession();
289
 
        }
290
 
        onDeleteIncomplete: {
291
 
            app.deleteOldSessions(app.incompleteSessions, function() {
292
 
                pageStack.clear();
293
 
                pageStack.push(welcomePage);
294
 
                app.startSession();
295
 
            });
296
 
        }
297
 
    }
298
 
 
299
 
    SelectionPage {
300
 
        id: testplanSelectionPage
301
 
        title: i18n.tr("Select test plan")
302
 
        onlyOneAllowed: true
303
 
        largeBuffer: args.values["autopilot"]
304
 
 
305
 
        function setup(testplan_info_list) {
306
 
            if (testplan_info_list.length<1) {
307
 
                ErrorLogic.showError(mainView, "Test plan missing", Qt.quit);
308
 
            }
309
 
 
310
 
            model.clear();
311
 
            for (var i=0; i<testplan_info_list.length; i++) {
312
 
                var testplan_info = testplan_info_list[i];
313
 
                model.append(testplan_info);
314
 
            }
315
 
            modelUpdated();
316
 
            pageStack.push(testplanSelectionPage);
317
 
        }
318
 
        onSelectionDone: {
319
 
            app.rememberTestplan(selected_id_list[0], function(response) {
320
 
                categorySelectionPage.setup(unlatchContinue);
321
 
            });
322
 
        }
323
 
    }
324
 
 
325
 
    SelectionPage {
326
 
        id: categorySelectionPage
327
 
        objectName: "categorySelectionPage"
328
 
        title: i18n.tr("Select categories")
329
 
        largeBuffer: args.values["autopilot"]
330
 
 
331
 
        function setup(continuation) {
332
 
            app.getCategories(function(response) {
333
 
                var uncategorised_id = "2013.com.canonical.plainbox::uncategorised"
334
 
                if (response.category_info_list.length === 1 &&
335
 
                    response.category_info_list[0].mod_id == uncategorised_id) {
336
 
                    selectionDone(uncategorised_id);
337
 
                } else {
338
 
                    var category_info_list = response.category_info_list;
339
 
                    model.clear();
340
 
                    for (var i=0; i<category_info_list.length; i++) {
341
 
                        var category_info = category_info_list[i];
342
 
                        model.append(category_info);
343
 
                    }
344
 
                    modelUpdated();
345
 
                    pageStack.push(categorySelectionPage);
346
 
                }
347
 
                // if called from welcome page, no continuation is given
348
 
                if (continuation) continuation();
349
 
            });
350
 
        }
351
 
 
352
 
        onSelectionDone: {
353
 
            app.rememberCategorySelection(selected_id_list, function(response) {
354
 
                testSelectionPage.setup(unlatchContinue);
355
 
            });
356
 
        }
357
 
 
358
 
    }
359
 
 
360
 
    SelectionPage {
361
 
        id: testSelectionPage
362
 
        objectName: "testSelectionPage"
363
 
        title: i18n.tr("Select tests")
364
 
        continueText: i18n.tr("Start testing")
365
 
        largeBuffer: args.values["autopilot"]
366
 
 
367
 
        function setup(continuation) {
368
 
            app.getTests(function(response) {
369
 
                model.clear();
370
 
                var test_info_list = response.test_info_list;
371
 
                for (var i=0; i<test_info_list.length; i++) {
372
 
                    model.append(test_info_list[i]);
373
 
                }
374
 
                modelUpdated();
375
 
                pageStack.push(testSelectionPage);
376
 
                continuation();
377
 
            });
378
 
        }
379
 
        
380
 
        onSelectionDone: {
381
 
            app.rememberTestSelection(selected_id_list, function() {
382
 
                processNextTest();
383
 
                unlatchContinue();
384
 
            });
385
 
        }
386
 
    }
387
 
 
388
 
    SelectionPage {
389
 
        id: rerunSelectionPage
390
 
        objectName: "rerunSelectionPage"
391
 
        title: i18n.tr("Select tests to re-run")
392
 
        continueText: state == "empty selection" ?
393
 
            i18n.tr("Finish") : i18n.tr("Re-run")
394
 
        emptyAllowed: true
395
 
        largeBuffer: args.values["autopilot"]
396
 
 
397
 
        function setup(rerunCandidates, continuation) {
398
 
            model.clear();
399
 
            for (var i=0; i<rerunCandidates.length; i++) {
400
 
                model.append(rerunCandidates[i]);
401
 
            }
402
 
            modelUpdated();
403
 
            pageStack.push(rerunSelectionPage)
404
 
        }
405
 
        onSelectionDone: {
406
 
            if (!selected_id_list.length) {
407
 
                showResultsScreen();
408
 
                unlatchContinue();
409
 
                return;
410
 
            }
411
 
            app.rememberTestSelection(selected_id_list, function() {
412
 
                processNextTest();
413
 
                unlatchContinue();
414
 
            });
415
 
        }
416
 
    }
417
 
    CommentsDialog {
418
 
        id: commentsDialog
419
 
    }
420
 
 
421
 
    PasswordDialog {
422
 
        id: passwordDialog
423
 
    }
424
 
 
425
 
    CommandOutputPage {
426
 
        id: commandOutputPage
427
 
        visible: false
428
 
        __customHeaderContents: progressHeader;
429
 
    }
430
 
    /*
431
 
     * Create a page from a Component defined in `url` with a common
432
 
     * progress header if `test` is supplied.
433
 
     * If Component definition has errors, display a proper popup.
434
 
     */
435
 
    function createPage(url, test) {
436
 
        var pageComponent = Qt.createComponent(Qt.resolvedUrl(url));
437
 
        if (pageComponent.status == Component.Error) {
438
 
            var msg = i18n.tr("Could not create component '") + url + "'\n" + pageComponent.errorString();
439
 
            console.error(msg);
440
 
            ErrorLogic.showError(mainView, msg, Qt.quit, i18n.tr("Quit"));
441
 
        } else {
442
 
            var pageObject = pageComponent.createObject();
443
 
            if (test) {
444
 
                pageObject.test = test;
445
 
                pageObject.__customHeaderContents = progressHeader;
446
 
                progressHeader.update(test)
447
 
            }
448
 
            return pageObject;
449
 
        }
450
 
    }
451
 
 
452
 
    function resumeOrStartSession() {
453
 
        app.isSessionResumable(function(result) {
454
 
            if(result.resumable === true) {
455
 
                pageStack.clear();
456
 
                pageStack.push(resumeSessionPage);
457
 
            } else {
458
 
                if (result.errors_encountered) {
459
 
                    ErrorLogic.showError(mainView, i18n.tr("Could not resume session."),
460
 
                                         gcAndStartSession(),
461
 
                                         i18n.tr("Start new session"));
462
 
                } else {
463
 
                    gcAndStartSession();
464
 
                }
465
 
            }
466
 
        });
467
 
    }
468
 
 
469
 
    function processNextTest() {
470
 
        app.getNextTest(function(test) {
471
 
            pageStack.clear();
472
 
            if (test.plugin === undefined) { 
473
 
                return showResultsScreen();
474
 
            }
475
 
            if (test.user) {
476
 
                // running this test will require to be run as a different
477
 
                // user (therefore requiring user to enter sudo password)
478
 
                if (!appSettings.sudoPasswordProvided) {
479
 
                    // ask user for password
480
 
                    var rememberContinuation = function(pass) {
481
 
                        passwordDialog.passwordEntered.disconnect(rememberContinuation);
482
 
                        app.rememberPassword(pass, function(){
483
 
                            appSettings.sudoPasswordProvided = true;
484
 
                            performTest(test);
485
 
                        });
486
 
                    }
487
 
                    var cancelContinuation = function() {
488
 
                        passwordDialog.dialogCancelled.disconnect(cancelContinuation);
489
 
                        test.outcome = "skip";
490
 
                        completeTest(test);
491
 
                    };
492
 
                    passwordDialog.passwordEntered.connect(rememberContinuation);
493
 
                    passwordDialog.dialogCancelled.connect(cancelContinuation);
494
 
                    PopupUtils.open(passwordDialog.dialogComponent);
495
 
                    return;
496
 
                }
497
 
            }
498
 
            performTest(test);
499
 
        });
500
 
    }
501
 
 
502
 
    function performTest(test) {
503
 
        switch (test['plugin']) {
504
 
            case 'manual':
505
 
                performManualTest(test);
506
 
                break;
507
 
            case 'user-interact-verify':
508
 
                performUserInteractVerifyTest(test);
509
 
                break;
510
 
            case 'local':
511
 
            case 'shell':
512
 
            case 'attachment':
513
 
            case 'resource':
514
 
                performAutomatedTest(test);
515
 
                break;
516
 
            case 'user-verify':
517
 
                performUserVerifyTest(test);
518
 
                break;
519
 
            case 'user-interact':
520
 
                performUserInteractTest(test);
521
 
                break;
522
 
            case 'qml':
523
 
                if (test.flags.indexOf("confined") > -1)
524
 
                    performConfinedQmlTest(test);
525
 
                else
526
 
                    performQmlTest(test);
527
 
                break;
528
 
            default:
529
 
                test.outcome = "skip";
530
 
                completeTest(test);
531
 
        }
532
 
    }
533
 
 
534
 
    function completeTest(test) {
535
 
        app.registerTestResult(test, processNextTest);
536
 
    }
537
 
 
538
 
    function runTestActivity(test, continuation) {
539
 
        commandOutputPage.clear();
540
 
        app.runTestActivity(test, continuation);
541
 
 
542
 
    }
543
 
 
544
 
    function showResultsScreen() {
545
 
        var endTesting = function() {
546
 
            pageStack.clear();
547
 
            app.clearSession(function() {
548
 
                gcAndStartSession();
549
 
                pageStack.push(welcomePage);
550
 
            });
551
 
        };
552
 
        var saveReport = function() {
553
 
            app.exportResults('2013.com.canonical.plainbox::html', [], function(uri) {
554
 
                var htmlReportUrl = uri;
555
 
                app.exportResults('2013.com.canonical.plainbox::xlsx', ["with-sys-info", "with-summary", "with-job-description", "with-text-attachments", "with-unit-categories"], function(uri) {
556
 
                    CbtDialogLogic.showDialog(mainView, i18n.tr("Reports have been saved to your Documents folder"),
557
 
                                              [{ "text": i18n.tr("OK"), "color": UbuntuColors.green}, {"text": i18n.tr("View Report"), "color": UbuntuColors.green, "onClicked": function(uri) {
558
 
                                                  var webviewer = Qt.createComponent(Qt.resolvedUrl("components/WebViewer.qml")).createObject();
559
 
                                                  webviewer.uri = htmlReportUrl;
560
 
                                                  pageStack.push(webviewer);
561
 
                                              }}]);
562
 
                });
563
 
            });
564
 
        };
565
 
        var submitReport = function(resultsPage) {
566
 
            // resultsPage param is for having control over unlatching
567
 
            getSubmissionInput(function() {
568
 
                app.submitResults(appSettings["submission"], function(reply) {
569
 
                    // pretty-stringify reply
570
 
                    var s = ""
571
 
                    for (var i in reply) {
572
 
                        s += i + ': ' + reply[i] + '\n';
573
 
                    }
574
 
                    CbtDialogLogic.showDialog(
575
 
                        resultsPage,
576
 
                        i18n.tr("Report has been submited.\n" + s),
577
 
                        [{"text": i18n.tr("OK"), "color": UbuntuColors.green}]);
578
 
                },
579
 
                function(error) {
580
 
                    ErrorLogic.showError(mainView,
581
 
                                         i18n.tr("Could not submit results. Reason:\n" + error),
582
 
                                         function(){},
583
 
                                         i18n.tr("OK"));
584
 
                    resultsPage.unlatchSubmission();
585
 
                })
586
 
            },
587
 
            function() {
588
 
                resultsPage.unlatchSubmission();
589
 
            });
590
 
        };
591
 
 
592
 
        pageStack.clear();
593
 
        app.getRerunCandidates(function(rerunCandidates) {
594
 
            app.getResults(function(results) {
595
 
                var resultsPage = createPage("components/ResultsPage.qml");
596
 
                resultsPage.results = results;
597
 
                if (appSettings["submission"]) {
598
 
                    resultsPage.submissionName = appSettings["submission"].name;
599
 
                }
600
 
                resultsPage.endTesting.connect(endTesting);
601
 
                resultsPage.saveReportClicked.connect(saveReport);
602
 
                resultsPage.submitReportClicked.connect(function() {submitReport(resultsPage);});
603
 
                if (rerunCandidates.length>0) {
604
 
                    resultsPage.rerunEnabled = true;
605
 
                    resultsPage.rerunTests.connect(function() {
606
 
                        rerunSelectionPage.setup(rerunCandidates);
607
 
                    });
608
 
                }
609
 
                pageStack.push(resultsPage);
610
 
            });
611
 
        });
612
 
    }
613
 
 
614
 
    function performAutomatedTest(test) {
615
 
        var automatedTestPage = createPage("components/AutomatedTestPage.qml", test);
616
 
        pageStack.push(automatedTestPage);
617
 
        runTestActivity(test, completeTest);
618
 
    }
619
 
 
620
 
    function performManualTest(test) {
621
 
        runTestActivity(test, function(test) {
622
 
            var manualIntroPage = createPage("components/ManualIntroPage.qml", test);
623
 
            manualIntroPage.testDone.connect(completeTest);
624
 
            manualIntroPage.continueClicked.connect(function() { showVerificationScreen(test); });
625
 
            pageStack.push(manualIntroPage);
626
 
        });
627
 
    }
628
 
 
629
 
    function performUserInteractVerifyTest(test) {
630
 
        var InteractIntroPage = createPage("components/InteractIntroPage.qml", test);
631
 
        InteractIntroPage.testStarted.connect(function() {
632
 
            runTestActivity(test, function(test) {
633
 
                InteractIntroPage.stopActivity();
634
 
                showVerificationScreen(test);
635
 
            });
636
 
        });
637
 
        InteractIntroPage.testDone.connect(completeTest);
638
 
        pageStack.push(InteractIntroPage);
639
 
    }
640
 
 
641
 
    function performUserInteractTest(test) {
642
 
        var InteractIntroPage = createPage("components/InteractIntroPage.qml", test);
643
 
        InteractIntroPage.testStarted.connect(function() {
644
 
            runTestActivity(test, function(test) {
645
 
                InteractIntroPage.stopActivity();
646
 
                var userInteractSummaryPage = createPage("components/UserInteractSummaryPage.qml", test);
647
 
                userInteractSummaryPage.testDone.connect(completeTest);
648
 
                pageStack.push(userInteractSummaryPage);
649
 
            });
650
 
        });
651
 
        InteractIntroPage.testDone.connect(completeTest);
652
 
        pageStack.push(InteractIntroPage);
653
 
    }
654
 
 
655
 
    function performUserVerifyTest(test) {
656
 
        var InteractIntroPage = createPage("components/InteractIntroPage.qml", test);
657
 
        InteractIntroPage.testDone.connect(completeTest);
658
 
        InteractIntroPage.testStarted.connect(function() {
659
 
            runTestActivity(test, function(test) { showVerificationScreen(test); } );
660
 
        });
661
 
        pageStack.push(InteractIntroPage);
662
 
    }
663
 
 
664
 
    function performQmlTest(test) {
665
 
        runTestActivity(test, function(test) {
666
 
            var qmlNativePage = createPage("components/QmlNativePage.qml", test);
667
 
            qmlNativePage.testDone.connect(completeTest);
668
 
            pageStack.push(qmlNativePage);
669
 
        });
670
 
    }
671
 
    function performConfinedQmlTest(test) {
672
 
        runTestActivity(test, function(test) {
673
 
            var qmlNativePage = createPage("components/QmlConfinedPage.qml", test);
674
 
            qmlNativePage.applicationVersion = app.applicationVersion;
675
 
            qmlNativePage.testDone.connect(completeTest);
676
 
            pageStack.push(qmlNativePage);
677
 
        });
678
 
    }
679
 
 
680
 
    function showVerificationScreen(test) {
681
 
        var verificationPage = createPage("components/TestVerificationPage.qml", test);
682
 
        var maybeCommentVerification = function(test) {
683
 
            if (test.outcome == 'fail' &&
684
 
                test.flags.indexOf('explicit-fail') > -1) {
685
 
                commentsDialog.commentDefaultText = test["comments"] || "";
686
 
                commentsDialog.commentAdded.connect(function(comment) {
687
 
                    test["comments"] = comment;
688
 
                    completeTest(test);
689
 
                });
690
 
                PopupUtils.open(commentsDialog.dialogComponent);
691
 
            } else {
692
 
                completeTest(test);
693
 
            }
694
 
        }
695
 
        verificationPage.testDone.connect(maybeCommentVerification);
696
 
        pageStack.push(verificationPage);
697
 
    }
698
 
    function getSubmissionInput(continuation, cancelContinuation) {
699
 
        if (appSettings.submission.inputForm) {
700
 
            var dlg_cmp = Qt.createComponent(Qt.resolvedUrl(appSettings.submission.inputForm));
701
 
            var dlg = dlg_cmp.createObject(mainView);
702
 
 
703
 
            dlg.cancelClicked.connect(function() {
704
 
                cancelContinuation();
705
 
                return;
706
 
            });
707
 
 
708
 
            dlg.submissionDetailsFilled.connect(function(submissionDetails) {
709
 
                for (var attr in submissionDetails) {
710
 
                    appSettings.submission[attr] = submissionDetails[attr];
711
 
                }
712
 
                continuation();
713
 
            });
714
 
            PopupUtils.open(dlg.dialogComponent);
715
 
            return; // inputForm gets precedence over input
716
 
        }
717
 
 
718
 
        if (!appSettings.submission.input) {
719
 
            // no input to process
720
 
            continuation();
721
 
            return;
722
 
        }
723
 
        var input_vars = appSettings.submission.input.slice(); //copy array
724
 
 
725
 
        // Because of the asynchronous nature of qml we cannot just launch
726
 
        // N number of popups each asking for one submission variable
727
 
        var process_input = function() {
728
 
            if (input_vars.length > 0) {
729
 
                var input = input_vars.shift();
730
 
                var dlg = Qt.createComponent(Qt.resolvedUrl("components/InputDialog.qml")).createObject(mainView);
731
 
                dlg.prompt = input.prompt;
732
 
                dlg.textEntered.connect(function(text) {
733
 
                    appSettings.submission[input.paramName] = text;
734
 
                    process_input();
735
 
                });
736
 
                dlg.cancelClicked.connect(function() {
737
 
                    cancelContinuation();
738
 
                    return;
739
 
                });
740
 
                PopupUtils.open(dlg.dialogComponent);
741
 
                return;
742
 
            }
743
 
            continuation();
744
 
        }
745
 
        process_input();
746
 
    }
747
 
    function gcAndStartSession() {
748
 
        // delete sessions that won't be resumed (NOT incomplete sessions)
749
 
        // and start a new session
750
 
        app.deleteOldSessions([], function() {
751
 
            app.startSession();
752
 
        });
753
 
    }
754
 
 
755
 
}