configurationengine/source/testautomation/testautomation/base_testcase.py
changeset 0 2e8eeb919028
child 3 e7e0ae78773e
equal deleted inserted replaced
-1:000000000000 0:2e8eeb919028
       
     1 #
       
     2 # Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 # All rights reserved.
       
     4 # This component and the accompanying materials are made available
       
     5 # under the terms of "Eclipse Public License v1.0"
       
     6 # which accompanies this distribution, and is available
       
     7 # at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 #
       
     9 # Initial Contributors:
       
    10 # Nokia Corporation - initial contribution.
       
    11 #
       
    12 # Contributors:
       
    13 #
       
    14 # Description: 
       
    15 #
       
    16 
       
    17 import sys, os, re, unittest, shutil, zipfile, filecmp, subprocess
       
    18 
       
    19 class BaseTestCase(unittest.TestCase):
       
    20     def set_modification_reference_time(self, path):
       
    21         """
       
    22         Set modification reference time for a subsequent call to assert_modified()
       
    23         or assert_not_modified().
       
    24         @param path: The path to use, can be a file or a directory.
       
    25         """
       
    26         if not hasattr(self, '_mod_refs'):
       
    27             self._mod_refs = {}
       
    28         
       
    29         if os.path.isdir(path):
       
    30             self._mod_refs[path] = self._get_dir_modtime_dict(path)
       
    31         elif os.path.isfile(path):
       
    32             self._mod_refs[path] = os.stat(path).st_mtime
       
    33         else:
       
    34             self.fail("'%s' does not exist" % path)
       
    35     
       
    36     def assert_modified(self, path):
       
    37         """
       
    38         Assert that a given file or directory has been modified since the last
       
    39         call to set_modification_reference_time() with the same path.
       
    40         """
       
    41         self._assert_modification(path, assert_not_modified=False)
       
    42     
       
    43     def assert_not_modified(self, path):
       
    44         """
       
    45         Assert that a given file or directory has NOT been modified since the last
       
    46         call to set_modification_reference_time() with the same path.
       
    47         """
       
    48         self._assert_modification(path, assert_not_modified=True)
       
    49     
       
    50     def remove_if_exists(self, path_or_paths):
       
    51         """Remove files or directories if they exist.
       
    52         @param path_or_paths: The path to remove. Can also be a list of paths."""
       
    53         if isinstance(path_or_paths, list):
       
    54             paths = path_or_paths
       
    55         else:
       
    56             paths = [path_or_paths]
       
    57         
       
    58         for path in paths:
       
    59             if os.path.isdir(path):
       
    60                 shutil.rmtree(path)
       
    61             elif os.path.isfile(path):
       
    62                 os.remove(path)
       
    63     
       
    64     def create_dir(self, path):
       
    65         """Create the given directory if it doesn't exist."""
       
    66         if not os.path.exists(path):
       
    67             os.makedirs(path)
       
    68     
       
    69     def recreate_dir(self, path):
       
    70         """Remove the given directory if it exists, and recreate it."""
       
    71         if os.path.exists(path):
       
    72             shutil.rmtree(path)
       
    73         os.makedirs(path)
       
    74     
       
    75     def create_dir_for_file_path(self, path):
       
    76         """Create the directories for the given file"""
       
    77         dir = os.path.dirname(path)
       
    78         if dir != '' and not os.path.exists(dir):
       
    79             os.makedirs(dir)
       
    80     
       
    81     def assert_exists_and_contains_something(self, path):
       
    82         """
       
    83         Assert that the given path is a file or a directory and contains some data.
       
    84         """
       
    85         if os.path.isdir(path):
       
    86             if len(os.listdir(path)) == 0:
       
    87                 self.fail("Path '%s' exists (is a directory) but does not contain anything)" % path)
       
    88         elif os.path.isfile(path):
       
    89             if os.stat(path).st_size == 0:
       
    90                 self.fail("Path '%s' exists (is a file) but does not contain anything)" % path)
       
    91         else:
       
    92             self.fail("Path '%s' does not exist" % path)
       
    93     
       
    94     def assert_dir_contents_equal(self, dir1, dir2, ignore=[], custom_comparison_functions={}, current_root_dir=''):
       
    95         """
       
    96         Assert recursively that the contents of two directories are equal.
       
    97         @param ignore: List containing names that should be ignored in the comparison (e.g. '.svn').
       
    98             The entries can either be relative, e.g. 'file.txt', which would ignore 'file.txt'
       
    99             in any directory, or they can be absolute, e.g. '/some/dir/file.txt', which would
       
   100             ignore 'file.txt' only under 'some/dir/', relative to the comparison root.
       
   101         @param custom_comparison_functions: Dictionary containing custom comparison functions
       
   102             for files. Each entry in the dict should contain the following contents:
       
   103                 Key: The relative path of the file under the directories, e.g.
       
   104                     'some/path/file.txt'
       
   105                 Value: The function used to compare the file contents. The function should
       
   106                     take as parameters the raw binary data of the files, and should return
       
   107                     True if the contents are equal.
       
   108         @param current_root_dir: For internal use.
       
   109         """
       
   110         msg = "Directory contents are not equal ('%s' vs. '%s')\n" % (dir1, dir2)
       
   111         
       
   112         ignore_list = []
       
   113         for entry in ignore:
       
   114             if entry.startswith('/'):
       
   115                 dirname, entryname = entry.rsplit('/', 1)
       
   116                 dirname = dirname.lstrip('/')
       
   117                 #print "dirname = %r" % dirname
       
   118                 #print "entryname = %r" % entryname
       
   119                 #print "current_root_dir = %r" % current_root_dir
       
   120                 if dirname == current_root_dir.rstrip('/'):
       
   121                     ignore_list.append(entryname)
       
   122             else:
       
   123                 ignore_list.append(entry)
       
   124 
       
   125         # Compare files with the custom comparison functions if necessary
       
   126         for path, func in custom_comparison_functions.iteritems():
       
   127             dirname  = os.path.dirname(path).replace('\\', '/')
       
   128             filename = os.path.basename(path)
       
   129             
       
   130             filepath1 = os.path.join(dir1, filename)
       
   131             filepath2 = os.path.join(dir2, filename)
       
   132             
       
   133             # Compare if the file is in the current path and they both exist
       
   134             if dirname == current_root_dir and \
       
   135                 os.path.isfile(filepath1) and \
       
   136                 os.path.isfile(filepath2):
       
   137                 comp_result = func(
       
   138                     self.read_data_from_file(filepath1),
       
   139                     self.read_data_from_file(filepath2))
       
   140                 if not comp_result:
       
   141                     # The files are not equal -> fail
       
   142                     self.fail(msg + "File '%s' differs" % filename)
       
   143                 else:
       
   144                     # The files are equal -> ignore from dircmp comparison
       
   145                     ignore_list.append(filename)
       
   146         
       
   147         dcmp = filecmp.dircmp(dir1, dir2, ignore=ignore_list)
       
   148         self.assertEquals(0, len(dcmp.left_only), msg + "Files only on left: %s" % dcmp.left_only)
       
   149         self.assertEquals(0, len(dcmp.right_only), msg + "Files only on right: %s" % dcmp.right_only)
       
   150         self.assertEquals(0, len(dcmp.diff_files), msg + "Differing files: %s" % dcmp.diff_files)
       
   151         self.assertEquals(0, len(dcmp.funny_files), msg + "Funny files: %s" % dcmp.funny_files)
       
   152         # Recurse into sub-directories
       
   153         for d in dcmp.common_dirs:
       
   154             if current_root_dir:    cr = current_root_dir + '/' + d
       
   155             else:                   cr = d
       
   156             self.assert_dir_contents_equal(
       
   157                 os.path.join(dir1, d), os.path.join(dir2, d),
       
   158                 ignore, custom_comparison_functions, cr)
       
   159     
       
   160     def assert_file_contents_equal(self, file1, file2, ignore_patterns=[]):
       
   161         """
       
   162         Assert the the given two files exist and their contents are equal.
       
   163         @param ignore_patterns: List of regular expressions for portions of the
       
   164             file content to ignore in the comparison. The ignored parts are
       
   165             deleted from the files before actual comparison.
       
   166         """
       
   167         self.assertTrue(os.path.exists(file1), "File '%s' does not exist!" % file1)
       
   168         self.assertTrue(os.path.exists(file2), "File '%s' does not exist!" % file2)
       
   169         
       
   170         data1 = self.read_data_from_file(file1)
       
   171         data2 = self.read_data_from_file(file2)
       
   172         
       
   173         def remove_ignored(data, pattern_list):
       
   174             for i, pattern in enumerate(pattern_list):
       
   175                 data = re.sub(pattern, '{{{ignore_%d}}}' % i, data)
       
   176             return data
       
   177         data1 = remove_ignored(data1, ignore_patterns)
       
   178         data2 = remove_ignored(data2, ignore_patterns)
       
   179         
       
   180         if data1 != data2:
       
   181             if len(ignore_patterns) > 0:
       
   182                 self.write_data_to_file(file1 + '.comparetemp', data1)
       
   183                 self.write_data_to_file(file2 + '.comparetemp', data2)
       
   184                 self.fail("Data of the files '%s' and '%s' are not equal\nSee *.comparetemp files for the actual data that was compared." % (file1, file2))
       
   185             else:
       
   186                 self.fail("Data of the files '%s' and '%s' are not equal" % (file1, file2))
       
   187     
       
   188     def assert_file_content_equals(self, filepath, expected_data):
       
   189         """
       
   190         Assert that the content of the given file is equals to the given expected data.
       
   191         """
       
   192         self.assertTrue(os.path.exists(filepath), "'%s' does not exist!" % filepath)
       
   193         self.assertTrue(os.path.isfile(filepath), "'%s' is not a file!" % filepath)
       
   194         
       
   195         f = open(filepath, "rb")
       
   196         try:        filedata = f.read()
       
   197         finally:    f.close()
       
   198         
       
   199         if filedata != expected_data:
       
   200             msg = ("The content of the file '%s' is not what was expected!\n" % filepath) +\
       
   201                   ("Expected: %r\nActual: %r" % (expected_data, filedata))
       
   202             self.fail(msg)
       
   203     
       
   204     def assert_file_contains(self, filepath, data, encoding=None):
       
   205         """
       
   206         Assert that the given file contains the given text somewhere in its contents.
       
   207         @param filepath: Path to the file to check.
       
   208         @param data: The data the file is expected to contain.
       
   209         @param encoding: Encoding used to decode the contents of the file.
       
   210             If None, noe decoding is done.
       
   211         """
       
   212         self.assertTrue(os.path.exists(filepath), "'%s' does not exist!" % filepath)
       
   213         self.assertTrue(os.path.isfile(filepath), "'%s' is not a file!" % filepath)
       
   214         
       
   215         f = open(filepath, "rb")
       
   216         try:        filedata = f.read()
       
   217         finally:    f.close()
       
   218         
       
   219         if encoding is not None:
       
   220             filedata = filedata.decode(encoding)
       
   221         
       
   222         if not isinstance(data, list):
       
   223             data = [data]
       
   224         
       
   225         for entry in data:
       
   226             if not filedata.find(entry) != -1:
       
   227                 self.fail("The file '%s' does not contain the data '%s'" % (filepath, entry))
       
   228 
       
   229     def assert_file_does_not_contain(self, filepath, data, encoding=None):
       
   230         """
       
   231         Assert that the given file doesn't contain the given text somewhere in its contents.
       
   232         @param filepath: Path to the file to check.
       
   233         @param data: The data the file is expected to not contain.
       
   234         @param encoding: Encoding used to decode the contents of the file.
       
   235             If None, noe decoding is done.
       
   236         """
       
   237         self.assertTrue(os.path.exists(filepath), "'%s' does not exist!" % filepath)
       
   238         self.assertTrue(os.path.isfile(filepath), "'%s' is not a file!" % filepath)
       
   239         
       
   240         f = open(filepath, "rb")
       
   241         try:        filedata = f.read()
       
   242         finally:    f.close()
       
   243         
       
   244         if encoding is not None:
       
   245             filedata = filedata.decode(encoding)
       
   246         
       
   247         if not isinstance(data, list):
       
   248             data = [data]
       
   249         
       
   250         for entry in data:
       
   251             if not filedata.find(entry) == -1:
       
   252                 self.fail("The file '%s' contains the data '%s'" % (filepath, entry))
       
   253     
       
   254     def read_data_from_file(self, path):
       
   255         """Read the raw binary data from the given file."""
       
   256         f = open(path, "rb")
       
   257         try:        return f.read()
       
   258         finally:    f.close()
       
   259     
       
   260     def read_data_from_zip_file(self, path, entry):
       
   261         """Read the raw binary data from the given ZIP file with the given ZIP entry."""
       
   262         zf = zipfile.ZipFile(path, "r")
       
   263         try:        return zf.read(entry)
       
   264         finally:    zf.close()
       
   265     
       
   266     def write_data_to_file(self, path, data):
       
   267         """Write raw binary data into the given file."""
       
   268         f = open(path, "wb")
       
   269         try:        f.write(data)
       
   270         finally:    f.close()
       
   271     
       
   272     def run_command(self, command, expected_return_code=0):
       
   273         """
       
   274         Run the given command, asserting that it returns the expected value.
       
   275         @param command: The command to run.
       
   276         @param expected_return_code: The expected return code. Can be None if the return
       
   277             code doesn't matter.
       
   278         @return: The command output.
       
   279         """
       
   280         # Using shell=True on windows uses
       
   281         #    cmd.exe /c <command>
       
   282         # to run the actual command, and if cmd.exe sees that the first
       
   283         # character in the command is ", it strips that and a trailing ".
       
   284         # For this reason we add quotes to the command to prevent e.g.
       
   285         #   "C:\some\command.cmd" --some-arg "xyz"
       
   286         # from becoming
       
   287         #   C:\some\command.cmd" --some-arg "xyz
       
   288         if sys.platform == 'win32' and command.startswith('"'):
       
   289             command = '"' + command + '"'
       
   290         
       
   291         p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
       
   292         out, err = p.communicate()
       
   293         if expected_return_code is not None:
       
   294             self.assertTrue(p.returncode == expected_return_code,
       
   295                             "Could not execute command (%s)\n"\
       
   296                             "Return code is not what was expected (expected %d, got %d)\n"\
       
   297                             "Output: \n%s" % (command, expected_return_code, p.returncode, out))
       
   298         return out
       
   299     
       
   300     # =====================================================
       
   301     # Private helper methods
       
   302     # =====================================================
       
   303     
       
   304     def _get_dir_modtime_dict(self, dir_path):
       
   305         """
       
   306         Return a dictionary of all files and directories and their last
       
   307         modification times in a given directory.
       
   308         """
       
   309         refdict = {}
       
   310         for root, dirs, files in os.walk(dir_path):
       
   311             for f in files:
       
   312                 path = os.path.join(root, f)
       
   313                 refdict[path] = os.stat(path).st_mtime
       
   314             for d in dirs:
       
   315                 path = os.path.join(root, d)
       
   316                 refdict[path] = os.stat(path).st_mtime
       
   317         return refdict
       
   318     
       
   319     def _assert_modification(self, path, assert_not_modified=True):
       
   320         if os.path.isdir(path):
       
   321             if assert_not_modified:
       
   322                 self._assert_dir_not_modified(path)
       
   323             else:
       
   324                 self.assert_dir_modified(path)
       
   325         elif os.path.isfile(path):
       
   326             if assert_not_modified:
       
   327                 self._assert_file_not_modified(path)
       
   328             else:
       
   329                 self._assert_file_modified(path)
       
   330         else:
       
   331             self.fail("'%s' does not exist" % path)
       
   332     
       
   333     def _assert_dir_not_modified(self, dir_path):
       
   334         refdict = self._mod_refs[dir_path]
       
   335         curdict = self._get_dir_modtime_dict(dir_path)
       
   336         
       
   337         # If the keys of the dicts are not the same, the contents of the
       
   338         # dir have been modified (added or removed files/subdirs)
       
   339         self.assertEquals(curdict.keys(), refdict.keys())
       
   340         
       
   341         # Compare manually so that assertion error output shows the specific file/dir
       
   342         for path in curdict.iterkeys():
       
   343             self.assertEquals(curdict[path], refdict[path], "File or dir '%s' modified" % path)
       
   344     
       
   345     def assert_dir_modified(self, dir_path):
       
   346         refdict = self._mod_refs[dir_path]
       
   347         curdict = self._get_dir_modtime_dict(dir_path)
       
   348         
       
   349         self.assertNotEqual(curdict, refdict, "Directory '%s' has not been modified when it was expected to be" % dir_path)
       
   350     
       
   351     def _assert_file_not_modified(self, file_path):
       
   352         time1 = self._mod_refs[file_path]
       
   353         time2 = os.stat(file_path).st_mtime
       
   354         self.assertEquals(time1, time2,
       
   355             ("File '%s' was modified when it should not have been "+\
       
   356             "(mod time %f vs. %f)") % (file_path, time1, time2))
       
   357     
       
   358     def _assert_file_modified(self, file_path):
       
   359         time1 = self._mod_refs[file_path]
       
   360         time2 = os.stat(file_path).st_mtime
       
   361         self.assertNotEqual(time1, time2,
       
   362             ("File '%s' was modified not when it should have been "+\
       
   363             "(mod time %f vs. %f)") % (file_path, time1, time2))