[gnome-continuous] Add "memusage" task



commit 50a63f9755f6b5bfb859e4b24bf1ac3538669472
Author: Colin Walters <walters verbum org>
Date:   Sun Dec 8 17:08:45 2013 -0500

    Add "memusage" task
    
    This just runs massif on gnome-shell right now.
    
    To support this though, we need to also generate -devel-debug disk
    images, since that tree contains valgrind.  testbase.js defaults to
    using the -runtime disk.

 Makefile-ostbuild.am                 |    1 +
 src/js/tasks/task-builddisks.js      |    2 +-
 src/js/tasks/task-integrationtest.js |    2 +-
 src/js/tasks/task-memusage.js        |  101 ++++++++++++++++++++++++++++++++++
 src/js/tasks/testbase.js             |   53 +++++++++++++++---
 5 files changed, 149 insertions(+), 10 deletions(-)
---
diff --git a/Makefile-ostbuild.am b/Makefile-ostbuild.am
index 2ee96e2..b46ce63 100644
--- a/Makefile-ostbuild.am
+++ b/Makefile-ostbuild.am
@@ -96,6 +96,7 @@ jsosttasks_DATA= \
        src/js/tasks/task-builddisks.js \
        src/js/tasks/task-smoketest.js \
        src/js/tasks/task-integrationtest.js \
+       src/js/tasks/task-memusage.js \
        src/js/tasks/task-applicationstest.js \
        src/js/tasks/task-zdisks.js \
        src/js/tasks/testbase.js \
diff --git a/src/js/tasks/task-builddisks.js b/src/js/tasks/task-builddisks.js
index cd6503a..94c4b0b 100644
--- a/src/js/tasks/task-builddisks.js
+++ b/src/js/tasks/task-builddisks.js
@@ -46,7 +46,7 @@ const TaskBuildDisks = new Lang.Class({
 
     _imageSubdir: 'images',
     _inheritPreviousDisk: true,
-    _onlyTreeSuffixes: ['-runtime'],
+    _onlyTreeSuffixes: ['-runtime', '-devel-debug'],
 
     execute: function(cancellable) {
         let isLocal = this._buildName == 'local';
diff --git a/src/js/tasks/task-integrationtest.js b/src/js/tasks/task-integrationtest.js
index 06649a7..db10b7d 100644
--- a/src/js/tasks/task-integrationtest.js
+++ b/src/js/tasks/task-integrationtest.js
@@ -78,7 +78,7 @@ const TaskIntegrationTest = new Lang.Class({
         print(msg);
     },
 
-    _postQemu: function(cancellable) {
+    _postQemu: function(mntdir, cancellable) {
         let testsJson = Gio.File.new_for_path('installed-test-results.json');
         JSONUtil.writeJsonFileAtomic(testsJson, this._allTests, null);
 
diff --git a/src/js/tasks/task-memusage.js b/src/js/tasks/task-memusage.js
new file mode 100644
index 0000000..0d9cc0c
--- /dev/null
+++ b/src/js/tasks/task-memusage.js
@@ -0,0 +1,101 @@
+// -*- indent-tabs-mode: nil; tab-width: 2; -*-
+// Copyright (C) 2013 Colin Walters <walters verbum org>
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+
+const GLib = imports.gi.GLib;
+const OSTree = imports.gi.OSTree;
+const Gio = imports.gi.Gio;
+const Lang = imports.lang;
+const Format = imports.format;
+
+const GSystem = imports.gi.GSystem;
+
+const Builtin = imports.builtin;
+const ArgParse = imports.argparse;
+const ProcUtil = imports.procutil;
+const Task = imports.task;
+const TestBase = imports.tasks.testbase;
+const LibQA = imports.libqa;
+const JSUtil = imports.jsutil;
+const JSONUtil = imports.jsonutil;
+const FileUtil = imports.fileutil;
+
+const TaskMemusage = new Lang.Class({
+    Name: 'TaskMemusage',
+    Extends: TestBase.TestBase,
+
+    TaskDef: {
+        TaskName: "memusage",
+        TaskAfter: ['smoketest'],
+    },
+
+    TestTrees: ['-devel-debug'],
+    CompleteIdleWaitSeconds: 60,
+
+    RequiredMessageIDs: ["0ce153587afa4095832d233c17a88001" // gnome-session ok
+                        ],
+
+    FailedMessageIDs:   [],
+
+    _postQemu: function(mntdir, cancellable) {
+        let osname = this._buildData['snapshot']['osname'];
+        let varTmpDir = mntdir.resolve_relative_path('ostree/deploy/' + osname + '/var/tmp');
+        let copied = [];
+        print("Examining " + varTmpDir.get_path());
+        FileUtil.walkDir(varTmpDir, { nameRegex: /massif-gnome-shell.*/,
+                                      depth: 1 },
+                         function (path, cancellable) {
+                             let dest = Gio.File.new_for_path(path.get_basename());
+                             print("Copying " + dest.get_path());
+                             path.copy(dest, Gio.FileCopyFlags.OVERWRITE, cancellable, null, null);
+                             copied.push(dest);
+                         }, cancellable);
+        print("Copied " + copied.length + " massif data files");
+        for (let i = 0; i < copied.length; i++) {
+            let path = copied[i].get_path();
+            let context = new GSystem.SubprocessContext({ argv: ['ms_print', path ] });
+            context.set_stdout_file_path(path + '.txt');
+            let proc = new GSystem.Subprocess({ context: context });
+            proc.init(cancellable);
+            proc.wait_sync_check(cancellable);
+        }
+    },
+   
+    _prepareDisk: function(mntdir, arch, cancellable) {
+        let osname = this._buildData['snapshot']['osname'];
+        let [deployDir, deployEtcDir] = LibQA.getDeployDirs(mntdir, osname);
+        let shellPath = deployDir.resolve_relative_path('usr/bin/gnome-shell');
+        let shellDotRealPath = deployDir.resolve_relative_path('usr/bin/gnome-shell.real');
+        GSystem.file_rename(shellPath, shellDotRealPath, cancellable);
+        let massifWrapper = '#!/bin/sh\ntouch /var/tmp/massif-started;exec valgrind --tool=massif 
--smc-check=all --massif-out-file=/var/tmp/massif-gnome-shell.$$ /usr/bin/gnome-shell.real\n';
+        shellPath.replace_contents(massifWrapper, null, false,
+                                   Gio.FileCreateFlags.REPLACE_DESTINATION,
+                                   cancellable);
+        GSystem.file_chmod(shellPath, 493, cancellable);
+        print("Replaced " + shellPath.get_path() + " with massif wrapper");
+        let desktopFile = '[Desktop Entry]\n\
+Encoding=UTF-8\n\
+Name=Timed logout\n\
+Exec=/usr/bin/sh -c \'sleep 30; touch /var/tmp/timed-logout.done; killall gnome-session\'\n\
+Terminal=false\n\
+Type=Application\n';
+        let dest = deployEtcDir.resolve_relative_path('xdg/autostart/gnome-continuous-timed-logout.desktop');
+        GSystem.file_ensure_directory(dest.get_parent(), true, cancellable);
+        dest.replace_contents(desktopFile, null, false, Gio.FileCreateFlags.REPLACE_DESTINATION,
+                              cancellable);
+    }
+});
diff --git a/src/js/tasks/testbase.js b/src/js/tasks/testbase.js
index 2b86859..67ef22e 100644
--- a/src/js/tasks/testbase.js
+++ b/src/js/tasks/testbase.js
@@ -33,7 +33,6 @@ const JSUtil = imports.jsutil;
 const JSONUtil = imports.jsonutil;
 
 const TIMEOUT_SECONDS = 10 * 60;
-const COMPLETE_IDLE_WAIT_SECONDS = 10;
 
 const CommandSocketIface = '<node> \
 <interface name="org.gnome.Continuous.Command"> \
@@ -162,10 +161,10 @@ const TestOneDisk = new Lang.Class({
                 this._parentTask._handleMessage(data, this._cancellable);
             }
             if (this._countPendingRequiredMessageIds == 0 && !this._foundAllMessageIds) {
-                print("Found all required message IDs");
+                print("Found all required message IDs, waiting for " + 
this._parentTask.CompleteIdleWaitSeconds);
                 this._foundAllMessageIds = true;
                 this._parentTask._onSuccess();
-                GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, COMPLETE_IDLE_WAIT_SECONDS,
+                GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, this._parentTask.CompleteIdleWaitSeconds,
                                          Lang.bind(this, this._onFinalWait));
             } else {
                 this._readingJournal = true;
@@ -224,6 +223,12 @@ const TestOneDisk = new Lang.Class({
 
     _onQemuCommandComplete: function(datain, result) {
         let [response, len] = datain.read_line_finish_utf8(result);
+        let responseData = null;
+        try {
+            responseData = JSON.parse(response);
+        } catch (e) {}
+        if (responseData && responseData.error)
+            print("command response error=" + JSON.stringify(responseData.error));
         let onComplete = this._qmpCommandOutstanding.shift();
         if (this._qmpCommandOutstanding.length == 1)
             this._qmpIn.read_line_async(GLib.PRIORITY_DEFAULT, this._cancellable,
@@ -293,10 +298,20 @@ const TestOneDisk = new Lang.Class({
 
         if (isFinal) {
             print("Final screenshot complete");
-            this._loop.quit();
+            this._qmpCommand({"execute": "system_powerdown"},
+                             Lang.bind(this, this._onFinalPoweroff));
         }
     },
 
+    _onFinalPoweroff: function() {
+        print("Poweroff request sent");
+        GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 5,
+                                 Lang.bind(this, function() {
+                                     print("Poweroff timeout ");
+                                     this._loop.quit();
+                                 }));
+    },
+
     _screenshot: function(params) {
         params = Params.parse(params, { isFinal: false,
                                         name: null });
@@ -328,7 +343,7 @@ const TestOneDisk = new Lang.Class({
     },
 
     _onFinalWait: function() {
-        print("Final wait complete");
+        print("Final wait complete at " + GLib.DateTime.new_now_local().format('%c'));
 
         this._screenshot({ isFinal: true });
     },
@@ -498,9 +513,14 @@ const TestOneDisk = new Lang.Class({
 
         GLib.source_remove(timeoutId);
         
-        GSystem.shutil_rm_rf(diskClone, cancellable);
+        let [gfmnt, mntdir] = LibQA.newReadWriteMount(diskClone, cancellable);
+        try {
+            this._parentTask._postQemu(mntdir, cancellable);
+        } finally {
+            gfmnt.umount(cancellable);
+        }
 
-        this._parentTask._postQemu(cancellable);
+        //GSystem.shutil_rm_rf(diskClone, cancellable);
 
         if (this._failed) {
             throw new Error(this._failedMessage);
@@ -519,6 +539,9 @@ const TestBase = new Lang.Class({
         TaskAfter: ['builddisks'],
     },
 
+    TestTrees: ['-runtime'],
+    CompleteIdleWaitSeconds: 10,
+
     BaseRequiredMessageIDs: ["39f53479d3a045ac8e11786248231fbf", // graphical.target 
                              "f77379a8490b408bbe5f6940505a777b",  // systemd-journald
                             ],
@@ -548,7 +571,7 @@ const TestBase = new Lang.Class({
     _onSuccess: function() {
     },
 
-    _postQemu: function(cancellable) {
+    _postQemu: function(mntdir, cancellable) {
     },
 
     _screenshotTaken: function(path) {
@@ -572,9 +595,23 @@ const TestBase = new Lang.Class({
             }
             if (!JSUtil.stringEndswith(name, '.qcow2'))
                 continue;
+            let matches = false;
+            for (let i = 0; i < this.TestTrees.length; i++) {
+                let tree = this.TestTrees[i];
+                if (JSUtil.stringEndswith(name, tree + '.qcow2')) {
+                    matches = true;
+                    break;
+                }
+            }
+            if (!matches) {
+                print("Skipping disk " + name + " not in " + JSON.stringify(this.TestTrees));
+                continue;
+            }
             disksToTest.push(name);
         }
         e.close(null);
+        if (disksToTest.length == 0)
+            throw new Error("Didn't find any matching .qcow2 disks in " + currentImages.get_path());
         this._buildData = null;
         if (buildJson != null)
             this._buildData = JSONUtil.loadJson(buildJson, cancellable);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]