From 745b29ae9d3221871584ca42b26af5d8766c9e13 Mon Sep 17 00:00:00 2001
From: Hongqing Yang <hoyang@redhat.com>
Date: Fri, 9 Sep 2011 15:24:15 +0800
Subject: [PATCH] mediakit_sanity test

---
 tests/mediakit_sanity/control            |   19 +++
 tests/mediakit_sanity/control.autoqa     |   10 ++
 tests/mediakit_sanity/mediakit_sanity.py |  121 ++++++++++++++++++
 tests/mediakit_sanity/sanity.py          |  197 ++++++++++++++++++++++++++++++
 4 files changed, 347 insertions(+), 0 deletions(-)
 create mode 100644 tests/mediakit_sanity/control
 create mode 100644 tests/mediakit_sanity/control.autoqa
 create mode 100755 tests/mediakit_sanity/mediakit_sanity.py
 create mode 100755 tests/mediakit_sanity/sanity.py

diff --git a/tests/mediakit_sanity/control b/tests/mediakit_sanity/control
new file mode 100644
index 0000000..c5ede9d
--- /dev/null
+++ b/tests/mediakit_sanity/control
@@ -0,0 +1,19 @@
+# vim: set syntax=python
+# Notice: Most recent documentation is available at doc/control.template.
+TIME="SHORT"
+AUTHOR = "Hongqing YANG<hoyang@redhat.com>"
+DOC = """
+This is the media kit sanity test suite for Fedora. This covers the
+media kit sanity for DVD.iso, Live.iso, boot.iso, netinst.iso.
+The test cases covered by this test are:
+-Mediakit ISO size
+-Mediakit ISO Checksums
+-Mediakit FileConflict
+-Mediakit Repoclosure
+"""
+NAME = 'mediakit_sanity'
+TEST_CLASS = 'General'
+TEST_CATEGORY = 'Functional'
+TEST_TYPE = 'CLIENT'
+
+job.run_test('mediakit_sanity', config=autoqa_conf, **autoqa_args)
diff --git a/tests/mediakit_sanity/control.autoqa b/tests/mediakit_sanity/control.autoqa
new file mode 100644
index 0000000..de5629b
--- /dev/null
+++ b/tests/mediakit_sanity/control.autoqa
@@ -0,0 +1,10 @@
+# vim: set syntax=python
+# Notice: Most recent documentation is available at doc/control.autoqa.template.
+
+# we need hardware with KVM
+labels = ['virt_capable']
+
+# we want to run rats_install just for post-tree-compose
+if event in ['post-iso-build']:
+    execute = True
+
diff --git a/tests/mediakit_sanity/mediakit_sanity.py b/tests/mediakit_sanity/mediakit_sanity.py
new file mode 100755
index 0000000..484b439
--- /dev/null
+++ b/tests/mediakit_sanity/mediakit_sanity.py
@@ -0,0 +1,121 @@
+#!/usr/bin/python
+#
+# Copyright 2009, Red Hat, Inc.
+#
+# 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Author: Hongqing YANG (hoyang@redhat.com)
+
+import os
+from autoqa import rats, util, config
+from autoqa.virtguest import findhostbridge
+from autotest_lib.client.bin import utils
+from autotest_lib.client.common_lib import error
+from autotest_lib.client.bin.test_config import config_loader
+from autoqa.test import AutoQATest
+from autoqa.decorators import ExceptionCatcher
+
+class mediakit_sanity(AutoQATest):
+    version = 1
+
+    @ExceptionCatcher()
+    def initialize(self,isouri,name, config, **kwargs):
+        super(self.__class__, self).initialize(config)
+        # set self.detail.id
+        if name:
+            self.detail.id = "%s-%s" % (name, kwargs['arch'])
+        else:
+            self.detail.id =  os.path.basename(isouri)
+
+    @ExceptionCatcher()
+    def run_once(self, isouri, name, **kwargs):
+        super(self.__class__, self).run_once()
+
+        cmd = "./sanity.py -i %s -s %s -l %s" % (isouri, self.tmpdir, self.resultsdir)
+            
+        try:
+            out = utils.system_output(cmd + " 2>&1", retain_output=True)
+            self.log(out, printout=False)
+        except error.CmdError, e:
+            self.result = 'CRASHED'
+            out = e.result_obj.stdout
+            self.log(out, printout=False)
+
+	media_size_result = None
+        sha256checksum_result = None
+        md5checksum_result = None
+        repoclosure_result = ''
+        file_conflicts = []
+        conflicting_pkgs = []
+        conflicts_summary_detail = ''
+        hitmarker = False
+
+        for line in out.split('\n'):
+            line.strip()
+            if not hitmarker:
+                if line.startswith('the size of'):
+                    if line.find('fail') != -1:
+                        media_size_result = 'FAILED'
+                    elif line.find('pass') != -1:
+                        media_size_result = 'PASSED'
+                elif line.startswith('SHA256 checksum'):
+                    if line.find('fail') != -1:
+                        sha256checksum_result = 'FAILED'
+                    elif line.find('pass') != -1:
+                        sha256checksum_result = 'PASSED'
+                elif line.startswith('The media check is complete, the result is:'):
+                    if  line.find('FAIL') != -1:
+                        md5checksum_result = 'FAILED'
+                    elif  line.find('PASS') != -1:
+                        md5checksum_result = 'PASSED'
+                elif line.startswith('Checking Dependencies'):
+                    repoclosure_result ='PASSED'
+                elif line.startswith('  unresolved deps:'):
+                    repoclosure_result = 'FAILED'
+                elif line.startswith('== File conflicts'):
+                    hitmarker = True
+            elif hitmarker:
+                if line.startswith('start mediakit sanity check.'):
+                    hitmarker = False
+                elif line.startswith('  /'):
+                    file_conflicts.append(line[2:])
+                elif line != '':
+                    conflicting_pkgs.append(line)
+
+            if file_conflicts or conflicting_pkgs:
+                file_conflicts = sorted(file_conflicts)
+                conflicting_pkgs = sorted(conflicting_pkgs)
+        
+            self.write_test_keyval({'file_conflicts_count':len(file_conflicts),
+                                    'conflicting_pkgs_count':len(conflicting_pkgs)})
+
+        if conflicting_pkgs or file_conflicts or media_size_result == "FAILED" or sha256checksum_result == 'FAILED'\
+           or md5checksum_result == "FAILED" or repoclosure_result == "FAILED":
+            self.detail.result = 'FAILED'
+        else:
+            self.detail.result = 'PASSED'
+ 
+        self.detail.summary = '\n\tMedia size test result: ' + media_size_result
+        self.detail.summary += '\n\tSHA256 checksum result: ' + sha256checksum_result
+        self.detail.summary += '\n\tMD5 checksum result: ' + md5checksum_result
+        if repoclosure_result:
+            self.detail.summary += '\n\tRepoclosure check result: ' + repoclosure_result
+        if conflicting_pkgs:
+            self.detail.summary += ('\n\t%u packages with %u file conflicts' % (len(conflicting_pkgs),len(file_conflicts)))
+            conflicts_summary_detail = '= Conflicting pkgs =\n%s' % '\n'.join(conflicting_pkgs)
+            conflicts_summary_detail += '\n\n= File conflicts =\n%s' % '\n'.join(file_conflicts)
+
+        self.detail.log.summary_detail = conflicts_summary_detail
+
diff --git a/tests/mediakit_sanity/sanity.py b/tests/mediakit_sanity/sanity.py
new file mode 100755
index 0000000..9c54ece
--- /dev/null
+++ b/tests/mediakit_sanity/sanity.py
@@ -0,0 +1,197 @@
+#!/usr/bin/python
+#
+# Copyright 2011, Red Hat, Inc.
+#
+# 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Author: Hongqing YANG <hoyang@redhat.com>
+
+import re
+import sys
+import os
+import optparse
+import subprocess
+import hashlib
+from autoqa import rats
+
+def system_sanity():
+    returncode = subprocess.call("rpm -q isomd5sum", shell= True)
+    if returncode == 0:
+       return True
+    else:
+       return False
+
+def parse_args():
+    parser = rats.get_parser()
+    parser.add_option("-i","--image", action="store",
+                      help="specify iso image to check size,repoclose,file conflicts. Example: -i /path/to/xxx_DVD.iso")
+    parser.add_option("-c","--check", action="store",
+                      help="read SHA256 sums from the FILEs and check them. Example: -c Fedora-13-i386-CHECKSUM")
+    (opt, args) = parser.parse_args()
+
+    if opt.repo is None and opt.image is None and opt.check is None:
+        parser.print_help()
+        parser.error("You have to specify at least one option to start the test")
+
+    if not opt.check:
+        if "x86_64" in os.path.basename(opt.image):
+            arch = "x86_64"
+        elif "i386" in os.path.basename(opt.image):
+            arch = "i386"
+        elif "i686" in os.path.basename(opt.image):
+            arch = "i686"
+   
+    if not opt.check:
+        file_names = list_file_names(os.path.dirname(opt.image))
+        for file_name in file_names:
+            if re.match("^Fedora.*-%s.*-CHECKSUM$" % arch, file_name):
+                opt.check = os.path.join(os.path.dirname(opt.image),file_name)
+        if not opt.check:
+            parser.error("No CHECKSUM file is specified or found")
+    return opt
+
+def list_file_names(path):
+    file_names = []
+    file_names = os.listdir(path)
+    return file_names
+
+def get_iso_size(iso_path):
+    if os.path.exists(iso_path):
+        size = os.path.getsize(iso_path)
+        return size
+    else:
+        print "Invalid iso path."
+
+def check_iso_size(iso_path):
+    # Test Case: https://fedoraproject.org/wiki/QA:Testcase_Mediakit_ISO_Size
+    size = get_iso_size(iso_path)/1048576
+    iso_type = check_iso_type(iso_path)
+   # the image size differ
+    if iso_type == "DVD":
+        if size > 2 and size < 4483:
+            print "the size of %s is %uM. pass." %(iso_type, size)
+        else:
+            print "the size of %s is %uM. fail." %(iso_type, size)
+    elif iso_type == "boot":
+        if size >2 and size < 700:
+            print "the size of %s is %uM. pass." %(iso_type, size)
+        else:
+            print "the size of %s is %uM. fail." %(iso_type, size)
+    elif iso_type == "netinst":
+        if size >2 and size <700:
+            print "the size of %s is %uM. pass." %(iso_type, size)
+        else:
+            print "the size of %s is %uM. fail." %(iso_type, size)
+    elif iso_type == "Live":
+        if size >2 and size <954:
+            print "the size of %s is %uM. pass." %(iso_type, size)
+        else:
+            print "the size of %s is %uM. fail." %(iso_type, size)
+    else:
+        print "Invalid ISO type."
+
+def check_iso_type(iso_path):
+    if iso_path.find("DVD") != -1:
+        iso_type = "DVD"
+    elif iso_path.find("boot") !=-1:
+        iso_type = "boot"
+    elif iso_path.find("netinst") !=-1:
+        iso_type = "netinst"
+    elif iso_path.find("Live") !=-1:
+        iso_type = "Live"
+    else:
+        print "Invalid ISO type."
+
+    return  iso_type
+
+def validate_hash(checksums_file, iso_file, type="sha256"):
+    # Test Case: https://fedoraproject.org/wiki/QA:Testcase_Mediakit_ISO_Checksums
+    hasher = hashlib.new(type)
+    fi = open(iso_file)
+    print "Reading image:"
+    data = fi.read(8192)
+    while data:
+        hasher.update(data)
+        data = fi.read(8192)
+    hasher.update(data)
+    fi.close()
+    iso_hash = hasher.hexdigest()
+    print " %s SHA256 checksum is: %s " % (iso_file, iso_hash)
+    if open(checksums_file).read().find(iso_hash) !=-1:
+        print "SHA256 checksum of %s matches value in %s,pass " % (iso_file, checksums_file)
+    else:
+        print "SHA256 checksum of %s does not match the value in %s,fail " % (iso_file, checksums_file)
+
+    print "Validating MD5 checksum: "
+    args = ['checkisomd5','%s' % iso_file]
+    process = subprocess.Popen(args,shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    out, error = process.communicate()
+    print out
+    print error
+
+def check_repoclosure(repo):
+    #Test Case: https://fedoraproject.org/wiki/QA:Testcase_Mediakit_Repoclosure
+    args = ['repoclosure','--repofrompath','%s' % repo,'--newest','-t','-r','%s' % repo.split(",")[0]]
+    subprocess.call(args)
+
+def iso_to_repo(file_path, mount_dir):
+    counter = 1
+    repoid = "iso_repo_%u" % counter
+    mount_dir = os.path.join(mount_dir,repoid)
+    if not os.path.exists(mount_dir):
+        os.makedirs(mount_dir)
+    umount_iso(mount_dir)
+    print "\nGoing to mount %s on %s" % (file_path, mount_dir)
+    mount_iso(file_path, mount_dir)
+    iso_repoid = "%s,%s" %(repoid,mount_dir)
+    return iso_repoid
+
+def clean_iso_repo(myrepo, mount_dir):
+        subprocess.call('umount "%s"' % mount_dir,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
+        subprocess.call('rm -fr %s' % myrepo, shell=True)
+
+def mount_iso(iso_path, mount_dir):
+    subprocess.call("mount -o loop %s %s" %(iso_path, mount_dir), shell=True)
+
+def umount_iso(mount_dir):
+    subprocess.call("umount %s" % mount_dir,shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
+
+def check_fileconflicts(repo):
+    # Test Case: https://fedoraproject.org/wiki/QA:Testcase_Mediakit_FileConflicts
+    file_dir = os.path.split(os.path.realpath(__file__))[0]
+    args = ['python','%s/../conflicts/potential_conflict.py' % file_dir,'--repofrompath=%s' % repo,'-r','%s' % repo.split(",")[0]]
+    subprocess.call(args)
+
+if __name__ == "__main__":
+    
+    print "start mediakit sanity check."
+    # Environment sanity check
+    if not os.getuid() == 0 or not os.environ['LOGNAME'] == "root":
+        print "ERROR: this can't be run as a normal user (yet)"
+        sys.exit(1)
+    if not system_sanity():
+        sys.exit(1)
+    
+    print "parse command-line arguments"
+    opt = parse_args()
+
+    mount_dir  = "/tmp/autoqa/mount_dir/"
+    check_iso_size(opt.image)
+    validate_hash(opt.check, opt.image)
+    if check_iso_type(opt.image) == "DVD":
+        iso_repo = iso_to_repo(opt.image, mount_dir)
+        check_repoclosure(iso_repo)
+        check_fileconflicts(iso_repo)
+        clean_iso_repo(iso_repo.split(",")[1], iso_repo.split(",")[1])
-- 
1.7.6

