|
From: <bms...@us...> - 2009-07-01 19:25:08
|
Revision: 2661
http://morphix.svn.sourceforge.net/morphix/?rev=2661&view=rev
Author: bmsleight
Date: 2009-07-01 19:24:57 +0000 (Wed, 01 Jul 2009)
Log Message:
-----------
Adding Autotesting2. Python, xml and joy
Added Paths:
-----------
trunk/mmaker/utils/autotesting2/
trunk/mmaker/utils/autotesting2/README
trunk/mmaker/utils/autotesting2/autotesting.py
trunk/mmaker/utils/autotesting2/tests/
trunk/mmaker/utils/autotesting2/tests/local-test_morphix-lightgui.xml
trunk/mmaker/utils/autotesting2/tests/morphix-lightgui.xml
Added: trunk/mmaker/utils/autotesting2/README
===================================================================
--- trunk/mmaker/utils/autotesting2/README (rev 0)
+++ trunk/mmaker/utils/autotesting2/README 2009-07-01 19:24:57 UTC (rev 2661)
@@ -0,0 +1,99 @@
+AUTOTESTING README
+==================
+
+autotesting --tests=TESTS.XML
+
+This readme outlines the different tags used in TESTS.XML.
+
+EXAMPLE TESTS.XML
+=================
+
+<autotesting>
+ </tests>
+ <test>
+ <download>http://127.0.0.1/autotesting/debian-live-501-i386-xfce-desktop.iso</download>
+ <title>Debian Live (xfce)</title>
+ <description>Debian Live. Daily build of squeeze xfce iso.</description>
+ <background>http://git.debian.org/?p=debian-live/homepage.git;a=blob_plain;f=images/debian-live.png</background>
+ <frequency>daily</frequency>
+ <qemu>
+ <xscreen>800x600x24</xscreen>
+ <binary>qemu</binary>
+ <options>-cdrom</options>
+ <pause>10</pause>
+ <sendkeys>kp_enter</sendkeys>
+ <!-- Time to run qmeu -->
+ <time>600</time>
+ </qemu>
+ <output>
+ <!-- Number of test sets to keep -->
+ <keep>4</keep>
+ <root>/home/bms/autotesting/tests/</root>
+ <local>example-live/squeeze/xfce/</local>
+ <video>autotesting.ogv</video>
+ <screenshots>
+ <final>final-screenshot.png</final>
+ <montage>montage-of-video-frames.png</montage>
+ </screenshots>
+ </output>
+ </test>
+ </tests>
+</autotesting>
+
+
+LOOKING AT EACH TAG
+===================
+
+<download>http://127.0.0.1/autotesting/debian-live-501-i386-xfce-desktop.iso</download>
+The location of the image to be tested. This can be an iso or an USB image (img) or in fact anything that can be booted with qemu.
+
+<title>Debian Live (xfce)</title>
+<description>Debian Live. Daily build of squeeze xfce iso.</description>
+The title and description tags are used in the opening titles of the video and also useful when scanning a long tests.xml file.
+
+<background>http://git.debian.org/?p=debian-live/homepage.git;a=blob_plain;f=images/debian-live.png</background>
+The location of the background graphic used in the video.
+
+<frequency>daily</frequency>
+This can be daily, weekly or monthly. Daily, means that the test will be run every time. Weekly - the test will only be done if the current day is a Sunday. Monthly - the test will only be done on the 1st day of a month,
+
+<xscreen>800x600x24</xscreen>
+The width, height and colour depth of the xserver (Xvfb) in which to run qemu. Not at the minimum dimensions required for qemu are 800x600.
+
+<binary>qemu</binary>
+The qemu binary. This could be for example qemu-ppc64 or qemu-arm, to test images for different architectures.
+
+<options>-cdrom</options>
+The option to pass to qemu in conjunction with the image we are testing. In this example we are testing a iso, so we need the "-cdrom" option. For an img file you would use -hda.
+
+<pause>10</pause>
+Time to pause before sending keys presses.
+
+<sendkeys>kp_enter</sendkeys>
+Some iso and img require some user interaction to star the booting, normally just a enter being pressed. Useful for selecting different options from the grub menu. Use the qmeu sendkey command, send "kp_enter" - a keypad enter. To send multiple key presses, use a comma separated list. <sendkeys>down,down,kp_enter</sendkeys>.
+
+<time>600</time>
+Let qemu run for 600 seconds.
+
+<keep>4</keep>
+Number of test sets to keep. If frequency is weekly, and keep is 4, then any test set older than 4 weeks will be deleted.
+
+<root>/home/bms/autotesting/tests/</root>
+<local>example-live/squeeze/xfce/</local>
+A new directory will be created at /root/prefix/DATE/, in this example /home/bms/autotesting/tests/example-live/squeeze/xfce/2009-07-01/ and the output files will be stored in this directory. Another directory /root/current/prefix/ will be created, with symlinks to the latest output files, e.g. /home/bms/autotesting/tests/current/example-live/squeeze/xfce/.
+
+<video>autotesting.ogv</video>
+The output video file stored in the output directories (see <root> and <local>). File is a theora video, created by the wonderful application - recordmydeskptop.
+
+<final>final-screenshot.png</final>
+<montage>montage-of-video-frames.png</montage>
+The output file names stored in the output directories (see <root> and <local>) of a final screenshot of qemu and a montage of frames from the video. These can give a good idea of how successful the test was rather than viewing the whole video.
+
+
+REQUIRED APPLICATIONS
+=====================
+
+I will be trying to package autotesting - however for reference this following applications are required:-
+
+python, python-amara, wget, Xvfb, xloadimage, qemu, recordmydesktop, ffmpeg, imagemagick, gmessage
+
Added: trunk/mmaker/utils/autotesting2/autotesting.py
===================================================================
--- trunk/mmaker/utils/autotesting2/autotesting.py (rev 0)
+++ trunk/mmaker/utils/autotesting2/autotesting.py 2009-07-01 19:24:57 UTC (rev 2661)
@@ -0,0 +1,284 @@
+# -*- coding: utf-8 -*-
+#
+# autotesting - automatically test by video qemu booting.
+# Copyright (C) Brendan M. Sleight, et al. <bm...@ba...>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+
+from optparse import OptionParser
+import amara, datetime, os, shutil, subprocess, telnetlib, tempfile, time
+
+def displayNumber():
+ """Really a global we can change later to something better.
+ like automaticaly get the next free display number. """
+ return ":8"
+
+def log(message):
+ """ Print [date] message """
+ now = datetime.datetime.now()
+ print "[" + str(now) + "] " + str(message)
+
+def cronCheak(frequency):
+ """Check if the frequency (e.g. daily, weekly, mounthly is due to
+ be run at this time
+ returns boolean.
+ """
+ now = datetime.datetime.now()
+ if frequency == "Daily" or frequency == "daily":
+ return True
+ elif frequency == "Weekly" or frequency == "weekly":
+ if now.weekday() == 0:
+ return True
+ elif frequency == "Monthly" or frequency == "monthly":
+ if now.day == 1:
+ return True
+ return False
+
+def dateBasedOnFrequency(frequency, keep):
+ now = datetime.datetime.now()
+ if frequency == "Daily" or frequency == "daily":
+ days=1
+ elif frequency == "Weekly" or frequency == "weekly":
+ days=7
+ elif frequency == "Monthly" or frequency == "monthly":
+ # No date delta of month so near enough ...
+ days=30
+ old = now - datetime.timedelta(days=days*keep)
+ return old
+
+def parseTest(xml):
+ """ Get the xml file and load as a object usign amara
+ returns amaraObject"""
+ tests = amara.parse(xml)
+ return tests.autotesting.tests
+
+def wget(url):
+ """ Use wget to download a file
+ return fileObject"""
+ log("Downloading " + url)
+ tmpFile = tempfile.NamedTemporaryFile(prefix="autotesting_wget_")
+ L = ['wget', '-nv', str(url), '-O', tmpFile.name]
+ # Maybe do something with the retcode in the future.
+ retcode = subprocess.call(L)
+ return tmpFile
+
+def getDownloads(downloadURL, backgroundURL):
+ """ Create two temp files and download the main downlaod and
+ the background
+ return tempfile, tempfile"""
+ background = wget(str(backgroundURL))
+ download = wget(str(downloadURL))
+ return download, background
+
+def authorityFile():
+ """ Return a file containing "localhost"
+ """
+ authority = tempfile.NamedTemporaryFile(prefix="autotesting_authority_")
+ authority.write("localhost\n")
+ authority.close()
+ return authority
+
+def startXvfb(display, xscreen, background):
+ """Start a Xvfb instance. The host display for qemu to run inside.
+ then set the background image. Return ths PID of Xvfb
+ return interger"""
+ log("Starting Xvfb")
+ authority = authorityFile()
+ xvfbCommand = ["Xvfb", display, "-auth", authority.name, "-screen", "0", xscreen]
+ xvfb = subprocess.Popen(xvfbCommand)
+ log("Setting Xvfb background")
+ xloadimage = ["xloadimage", "-display", display, "-onroot", "-fullscreen", background]
+ retcode = subprocess.call(xloadimage)
+ return xvfb
+
+def waitUntilEncodingFinished(recordMyDesktop):
+ log("Waiting for recordmydesktop encoding to finish")
+ while recordMyDesktop.poll()!=0:
+ print ".. ",
+ time.sleep(1)
+ print " "
+
+def kill(process, message):
+ log(message)
+ kill = ["kill", str(process.pid)]
+ retcode = subprocess.call(kill)
+
+def startRecordMyDesktop(display):
+ log("Starting Record My Desktop")
+ video = tempfile.NamedTemporaryFile(prefix="autotesting_video_", suffix=".ogv")
+ recordmydesktopCommand = ["recordmydesktop", "--no-cursor", "-display",
+ display ,"--no-sound", "--overwrite", "-o" ,video.name]
+ recordmydesktop = subprocess.Popen(recordmydesktopCommand)
+ return recordmydesktop, video
+
+def xmessage(display, title, message, time, font):
+ xloadimage = ["gmessage", "-display", display, "-timeout", time,
+ "-font", font, "-button", "", "-title", title,
+ "-center", "\n" + message]
+ retcode = subprocess.call(xloadimage)
+
+def openingTitles(display, test):
+ log("Showing Opening Titles")
+ time.sleep(2)
+ xmessage(display, str(test.title), "Autotesting of: " + str(test.title), "3", "monospace 14")
+ xmessage(display, str(test.title), str(test.description), "3", "monospace 12")
+ xmessage(display, str(test.title), "Created at " + str(datetime.datetime.now()), "2", "monospace 10")
+
+def runningQemu(display, test, qemuDownload):
+ """ Start qemu running, with a local telnet port at 55555 listening acting as the qemu monitor
+ returns subprocess.process"""
+ telnet = ("127.0.0.1", "55555")
+ address, port = telnet
+ monitor = "telnet:" + address + ":" + port + ",server,nowait"
+ qemuBinary = str(test.qemu.binary)
+ log("Starting " + qemuBinary)
+ if not qemuBinary.startswith("qemu"):
+ log("WARNING! : " + qemuBinary + " does not start with qemu, using qemu instead.")
+ qemuBinary = "qemu"
+ qemuCommand = [qemuBinary, "-monitor", monitor, "-full-screen", str(test.qemu.options), str(qemuDownload)]
+ qemu = subprocess.Popen(qemuCommand, env={"DISPLAY": display})
+ sendkeysToQemu(test, telnet)
+ log("Running qemu for " + str(test.qemu.time) + " seconds")
+ time.sleep(int(str(test.qemu.time)))
+ return qemu
+
+def sendkeysToQemu(test, telnet):
+ """Using telnet to send commands to qemu monitor
+ """
+ address, port = telnet
+ log("Sending keys after pause of " + str(test.qemu.pause) + " seconds")
+ time.sleep(int(str(test.qemu.pause)))
+ tn = telnetlib.Telnet(address, port)
+ sendkeys = str(test.qemu.sendkeys)
+ for key in sendkeys.split(','):
+ log("qemu sendkey " + key)
+ tn.write("sendkey " + key + "\n")
+ time.sleep(1)
+
+
+def captureScreenshot(display):
+ """ Capture screen shot on display
+ return fileObject"""
+ log("Capture screenshot")
+ finalImage = tempfile.NamedTemporaryFile(prefix="autotesting_video_", suffix=".png")
+ captureCommand = ["import", "-display", display, "-window", "root", finalImage.name]
+ retcode = subprocess.call(captureCommand)
+ return finalImage
+
+def createMontage(video, test):
+ """ Make 16 frames of the video at 1/16, 2/16, 3/16 .... 16/16 of
+ way through the video. The make a montage of these frames in to
+ one image.
+ return fileObject"""
+ log("Creating Montage")
+ montage = tempfile.NamedTemporaryFile(prefix="autotesting_video_", suffix=".png")
+ videoLength = int(str(test.qemu.pause)) + int(str(test.qemu.time))
+ # Time for opening titles
+ videoLength = videoLength + 2 + 3 + 3 + 2
+ listFrames = []
+ listFramesNames = []
+ for count in range(16):
+ ss = 0.0625 * count * videoLength
+ frame = tempfile.NamedTemporaryFile(prefix="autotesting_frame_", suffix=".jpg")
+ frameName = frame.name + "%d.jpg"
+ frameNameOut = frame.name + "1.jpg"
+ ffmpeg = ["ffmpeg", "-i", video.name, "-an", "-ss", str(ss), "-t",
+ "01", "-r", "1", "-y", frameName]
+ retcode = subprocess.call(ffmpeg)
+ shutil.move(frameNameOut, frame.name)
+ listFramesNames.append(frame.name)
+ listFrames.append(frame)
+ montageCommand = ["montage", "-geometry", "180x135+4+4", "-frame", "5"]
+ for frame in listFramesNames:
+ montageCommand.append(frame)
+ montageCommand.append(montage.name)
+ retcode = subprocess.call(montageCommand)
+ return montage
+
+def storeFile(tmpFile, copyLocation, symLocation):
+ shutil.copyfile(tmpFile, copyLocation)
+ try:
+ os.remove(symLocation)
+ except:
+ pass
+ os.symlink(copyLocation, symLocation)
+
+def fileOutputs(test, video, finalImage, montage):
+ """ Move files to the correct place (as per XML tags)
+ including symlinks to current.
+ """
+ log("Moving files to the correct place.")
+ root=str(test.output.root)
+ local=str(test.output.local)
+ today=str(datetime.date.today())
+ mainDir = root + "/" + local + "/" + today + "/"
+ dateDirs = root + "/" + local + "/"
+ currentDir = root + "/current/" + local + "/"
+ try:
+ os.makedirs(mainDir)
+ except:
+ pass
+ try:
+ os.makedirs(currentDir)
+ except:
+ pass
+ storeFile(video.name, mainDir + str(test.output.video),
+ currentDir + str(test.output.video))
+ storeFile(finalImage.name, mainDir + str(test.output.screenshots.final),
+ currentDir + str(test.output.screenshots.final))
+ storeFile(montage.name, mainDir + str(test.output.screenshots.montage),
+ currentDir + str(test.output.screenshots.montage))
+ keepDate = dateBasedOnFrequency(str(test.frequency), int(str(test.output.keep)))
+ log("Removing old Autotesting output before " + keepDate.strftime("%A %B %d %I:%M:%S %p %Y"))
+ for f in os.listdir(dateDirs):
+ fp = dateDirs + f
+ if (time.mktime(keepDate.timetuple()) - os.path.getmtime(fp) ) > 0:
+ # Remove the old file
+ shutil.rmtree(fp)
+ log("Removing - " + fp)
+
+def main():
+ usage = "usage: %prog [options] --tests=TESTS.XML \n %prog --help for all options"
+ parser = OptionParser(usage, version="%prog ")
+ parser.add_option("-t", "--tests", dest="tests",
+ help="complete the autotesting definined in the xml template")
+ (options, args) = parser.parse_args()
+ if not options.tests :
+ parser.error("Must pass a list of tests to complete.")
+
+ # Main loop
+ display = displayNumber()
+ tests = parseTest(options.tests)
+ for test in tests.test:
+ if cronCheak(str(test.frequency)):
+ log("Starting Autotesting of: " + str(test.title))
+ (download, background) = getDownloads(str(test.download), str(test.background))
+ xvfb = startXvfb(display, str(test.qemu.xscreen), background.name)
+ (recordMyDesktop, video) = startRecordMyDesktop(display)
+ openingTitles(display, test)
+ qemu = runningQemu(display, test, download.name)
+ finalImage = captureScreenshot(display)
+ kill(qemu, "Killing qemu")
+ kill(recordMyDesktop, "Killing recordmysdesktop")
+ waitUntilEncodingFinished(recordMyDesktop)
+ kill(xvfb, "Killing Xvfb")
+ # Put video, montage in right place remvoe old versions etc.
+ montage = createMontage(video, test)
+ fileOutputs(test, video, finalImage, montage)
+ log("Finished Autotesting of: " + str(test.title))
+ log("*****************************")
+
+if __name__ == "__main__":
+ main()
Added: trunk/mmaker/utils/autotesting2/tests/local-test_morphix-lightgui.xml
===================================================================
--- trunk/mmaker/utils/autotesting2/tests/local-test_morphix-lightgui.xml (rev 0)
+++ trunk/mmaker/utils/autotesting2/tests/local-test_morphix-lightgui.xml 2009-07-01 19:24:57 UTC (rev 2661)
@@ -0,0 +1,32 @@
+<autotesting>
+ <tests>
+ <test>
+ <download>http://127.0.0.1/autotesting/lightgui-basemod-2.6.23-2008-02-10_0018-latest.iso</download>
+ <title>Morphix LightGUI</title>
+ <description>Morphix. Daily build of LightGUI iso.</description>
+ <background>http://www.morphix.org/templates/MorphixORG/images/mambo_header.jpg</background>
+ <frequency>daily</frequency>
+ <qemu>
+ <xscreen>800x600x24</xscreen>
+ <binary>qemu</binary>
+ <options>-cdrom</options>
+ <!-- Time to pause before sending keys presses -->
+ <pause>10</pause>
+ <sendkeys>down,down,kp_enter</sendkeys>
+ <!-- Time to run qmeu -->
+ <time>600</time>
+ </qemu>
+ <output>
+ <!-- Number of test sets to keep -->
+ <keep>4</keep>
+ <root>/home/bms/autotesting/tests/</root>
+ <local>morphix/lightGUI/</local>
+ <video>autotesting.ogv</video>
+ <screenshots>
+ <final>final-screenshot.png</final>
+ <montage>montage-of-video-frames.png</montage>
+ </screenshots>
+ </output>
+ </test>
+ </tests>
+</autotesting>
Added: trunk/mmaker/utils/autotesting2/tests/morphix-lightgui.xml
===================================================================
--- trunk/mmaker/utils/autotesting2/tests/morphix-lightgui.xml (rev 0)
+++ trunk/mmaker/utils/autotesting2/tests/morphix-lightgui.xml 2009-07-01 19:24:57 UTC (rev 2661)
@@ -0,0 +1,32 @@
+<autotesting>
+ <tests>
+ <test>
+ <download>http://distro.ibiblio.org/pub/linux/distributions/morphix/autobuilds/iso/lightgui-basemod-2.6.23-2008-02-10_0018-latest.iso</download>
+ <title>Morphix LightGUI</title>
+ <description>Morphix. Daily build of LightGUI iso.</description>
+ <background>http://www.morphix.org/templates/MorphixORG/images/mambo_header.jpg</background>
+ <frequency>daily</frequency>
+ <qemu>
+ <xscreen>800x600x24</xscreen>
+ <binary>qemu</binary>
+ <options>-cdrom</options>
+ <!-- Time to pause before sending keys presses -->
+ <pause>10</pause>
+ <sendkeys>down,down,kp_enter</sendkeys>
+ <!-- Time to run qmeu -->
+ <time>600</time>
+ </qemu>
+ <output>
+ <!-- Number of test sets to keep -->
+ <keep>4</keep>
+ <root>/home/bms/autotesting/tests/</root>
+ <local>morphix/lightGUI/</local>
+ <video>autotesting.ogv</video>
+ <screenshots>
+ <final>final-screenshot.png</final>
+ <montage>montage-of-video-frames.png</montage>
+ </screenshots>
+ </output>
+ </test>
+ </tests>
+</autotesting>
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|