configurationengine/source/scripts/tests/unittest_merge.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 """
       
    18 Test the configuration
       
    19 """
       
    20 import unittest
       
    21 import os
       
    22 import shutil
       
    23 import zipfile
       
    24 import __init__
       
    25 from testautomation.base_testcase import BaseTestCase
       
    26 from testautomation import unzip_file
       
    27 from scripttest_common import get_cmd
       
    28 
       
    29 try:
       
    30     from cElementTree import ElementTree
       
    31 except ImportError:
       
    32     try:    
       
    33         from elementtree import ElementTree
       
    34     except ImportError:
       
    35         try:
       
    36             from xml.etree import cElementTree as ElementTree
       
    37         except ImportError:
       
    38             from xml.etree import ElementTree
       
    39 
       
    40 ROOT_PATH = os.path.dirname(os.path.abspath(__file__))
       
    41 TESTDATA_DIR = os.path.join(ROOT_PATH, 'testdata/merge')
       
    42 TEMP_DIR = os.path.join(ROOT_PATH, 'temp/merge')
       
    43 TEST_PROJECT_CPF = os.path.join(ROOT_PATH, 'test_project.cpf')
       
    44 TEST_VARIANT_CPF = os.path.join(ROOT_PATH, 'test_variant.cpf')
       
    45 
       
    46 TEST_VARIANT_CPF_V1 = os.path.join(TESTDATA_DIR, 'test_variant_v1.cpf')
       
    47 TEST_VARIANT_CPF_V2 = os.path.join(TESTDATA_DIR, 'test_variant_v2.cpf')
       
    48 
       
    49 
       
    50 class TestMerge(BaseTestCase):
       
    51     
       
    52     def _prepare_workdir_with_project(self, workdir, expected_zip=None):
       
    53         """
       
    54         Prepare a working directory for running a test.
       
    55         @param workdir: Sub-directory of the workdir.
       
    56         @param expected_zip: Zip file containing expected data that should
       
    57             be extracted under the workdir, can be None. The path should be
       
    58             relative to testdata/merge.
       
    59         @return: Tuple (test_project_abs, expected_dir_abs). expected_dir_abs
       
    60             will be None if expected_zip was None.
       
    61         """
       
    62         workdir = os.path.join(TEMP_DIR, workdir)
       
    63         self.recreate_dir(workdir)
       
    64         
       
    65         # Unzip the test project
       
    66         test_project_dir = os.path.join(workdir, 'test_project')
       
    67         unzip_file.unzip_file(TEST_PROJECT_CPF, test_project_dir, delete_if_exists=True)
       
    68         
       
    69         # Check that it was unzipped correctly
       
    70         paths = [
       
    71             "Layer1/", "Layer2/","Layer3/", "Layer4/", "Layer5/",
       
    72             "root1.confml", "root2.confml", "root3.confml", "root4.confml", "root5.confml"
       
    73         ]
       
    74         for path in paths:
       
    75             self.assert_exists_and_contains_something(os.path.join(test_project_dir, path))
       
    76         
       
    77         expected_dir = None
       
    78         # Unzip the expected data
       
    79         if expected_zip:
       
    80             expected_zip = os.path.join(TESTDATA_DIR, expected_zip)
       
    81             expected_dir = os.path.join(workdir, 'expected')
       
    82             unzip_file.unzip_file(expected_zip, expected_dir)
       
    83         
       
    84         return test_project_dir, expected_dir
       
    85     
       
    86     def test_get_help(self):
       
    87         cmd = '%s -h' % get_cmd('merge')
       
    88         out = self.run_command(cmd)
       
    89         lines = out.split('\r\n')
       
    90         self.assertTrue('Options:' in lines)
       
    91         self.assertTrue('  Merge options:' in lines)
       
    92 
       
    93     def test_merge_cpf_last_layer_to_project(self):
       
    94         project_dir, expected_dir = self._prepare_workdir_with_project('last_layer_from_cpf', 'last_layer_expected.zip')
       
    95         
       
    96         self.set_modification_reference_time(project_dir)
       
    97         self.set_modification_reference_time(TEST_VARIANT_CPF)
       
    98         cmd = '%s -p "%s" -r "%s" -c root5.confml -l -1 -v 5'  % (get_cmd('merge'), project_dir, TEST_VARIANT_CPF)
       
    99         self.run_command(cmd)
       
   100         
       
   101         self.assert_modified(project_dir)
       
   102         self.assert_not_modified(TEST_VARIANT_CPF)
       
   103         self.assert_dir_contents_equal(expected_dir, project_dir)
       
   104     
       
   105     def test_merge_cpf_last_layer_to_project_with_rename(self):
       
   106         project_dir, expected_dir = self._prepare_workdir_with_project('last_layer_from_cpf_rename', 'last_layer_rename_expected.zip')
       
   107         
       
   108         self.set_modification_reference_time(project_dir)
       
   109         self.set_modification_reference_time(TEST_VARIANT_CPF)
       
   110         cmd = '%s -p "%s" -r "%s" -c root5.confml -l -1 -v 5 --rename'  % (get_cmd('merge'), project_dir, TEST_VARIANT_CPF)
       
   111         self.run_command(cmd)
       
   112         
       
   113         self.assert_modified(project_dir)
       
   114         self.assert_not_modified(TEST_VARIANT_CPF)
       
   115         self.assert_dir_contents_equal(expected_dir, project_dir)
       
   116     
       
   117     def test_merge_cpf_multiple_last_layers_to_project(self):
       
   118         project_dir, expected_dir = self._prepare_workdir_with_project('multiple_last_layers_from_cpf', 'multiple_last_layers_expected.zip')
       
   119         
       
   120         self.set_modification_reference_time(project_dir)
       
   121         self.set_modification_reference_time(TEST_VARIANT_CPF)
       
   122         # Pass the merged layers in random order to check that it doesn't affect
       
   123         # the output
       
   124         cmd = '%s -p "%s" -r "%s" -c root5.confml -l -3 -l -1 -l -2 -v 5'  % (get_cmd('merge'), project_dir, TEST_VARIANT_CPF)
       
   125         self.run_command(cmd)
       
   126         
       
   127         self.assert_modified(project_dir)
       
   128         self.assert_not_modified(TEST_VARIANT_CPF)
       
   129         self.assert_dir_contents_equal(expected_dir, project_dir)
       
   130         
       
   131     def test_merge_cpf_multiple_mixed_layers_to_project(self):
       
   132         project_dir, expected_dir = self._prepare_workdir_with_project('mixed_multiple_last_layers_from_cpf', 'multiple_last_layers_expected.zip')
       
   133         
       
   134         self.set_modification_reference_time(project_dir)
       
   135         self.set_modification_reference_time(TEST_VARIANT_CPF)
       
   136         cmd = '%s -p "%s" -r "%s" -c root5.confml -l -3 -l -1 -l 4 -l 5 -v 5'  % (get_cmd('merge'), project_dir, TEST_VARIANT_CPF)
       
   137         self.run_command(cmd)
       
   138         
       
   139         self.assert_modified(project_dir)
       
   140         self.assert_not_modified(TEST_VARIANT_CPF)
       
   141         self.assert_dir_contents_equal(expected_dir, project_dir)
       
   142                 
       
   143     def test_merge_layer_to_cpf(self):
       
   144         project_cpf = os.path.join(ROOT_PATH, "temp/merge/layer_to_cpf/project.cpf")
       
   145         self.create_dir_for_file_path(project_cpf)
       
   146         shutil.copy2(TEST_PROJECT_CPF, project_cpf)
       
   147         
       
   148         self.set_modification_reference_time(project_cpf)
       
   149         self.set_modification_reference_time(TEST_VARIANT_CPF)
       
   150         
       
   151         cmd = '%s -p "%s" -r "%s" -c root5.confml -l -1 -v 5'  % (get_cmd('merge'), project_cpf, TEST_VARIANT_CPF)
       
   152         self.run_command(cmd)
       
   153         
       
   154         def check(entry):
       
   155             zf = zipfile.ZipFile(project_cpf, "r")
       
   156             try:     self.assertTrue(entry in zf.namelist(), "Entry '%s' not in zip file '%s'" % (entry, project_cpf))
       
   157             finally: zf.close()
       
   158         check('variant/root.confml')
       
   159         check('variant/confml/data.confml')
       
   160         check('variant/content/empty/')
       
   161         
       
   162         self.assertEquals(
       
   163             self.get_xinclude_list(self.read_data_from_zip_file(project_cpf, "root5.confml")),
       
   164             ["Layer1/root.confml",
       
   165              "Layer2/root.confml",
       
   166              "Layer3/root.confml",
       
   167              "Layer4/root.confml",
       
   168              "Layer5/root.confml",
       
   169              "variant/root.confml"])
       
   170         
       
   171         self.assert_modified(project_cpf)
       
   172         self.assert_not_modified(TEST_VARIANT_CPF)
       
   173     
       
   174     def test_merge_cpf_last_layer_two_versions(self):
       
   175         project_dir, expected_dir = self._prepare_workdir_with_project('last_layer_two_versions', 'last_layer_variant_v1_v2_expected.zip')
       
   176         cmd = '%s -p "%s" -r "%s" -c root5.confml -l -1'  % (get_cmd('merge'), project_dir, TEST_VARIANT_CPF_V1)
       
   177         self.run_command(cmd)
       
   178         cmd = '%s -p "%s" -r "%s" -c root5.confml -l -1'  % (get_cmd('merge'), project_dir, TEST_VARIANT_CPF_V2)
       
   179         self.run_command(cmd)
       
   180         self.assert_dir_contents_equal(expected_dir, project_dir)
       
   181     
       
   182     def test_merge_cpf_last_layer_two_versions_overwrite_layer(self):
       
   183         project_dir, expected_dir = self._prepare_workdir_with_project('last_layer_two_versions_overwrite', 'last_layer_variant_v2_expected.zip')
       
   184         cmd = '%s -p "%s" -r "%s" -c root5.confml -l -1 --merge-policy overwrite-layer'  % (get_cmd('merge'), project_dir, TEST_VARIANT_CPF_V1)
       
   185         self.run_command(cmd)
       
   186         cmd = '%s -p "%s" -r "%s" -c root5.confml -l -1 --merge-policy overwrite-layer'  % (get_cmd('merge'), project_dir, TEST_VARIANT_CPF_V2)
       
   187         self.run_command(cmd)
       
   188         self.assert_dir_contents_equal(expected_dir, project_dir)
       
   189     
       
   190     def get_xinclude_list(self, confml_file_data):
       
   191         """
       
   192         Read the XInlude element list from a ConfML file and assert that.
       
   193         @param confml_file_data: The raw binary data of the ConfML file.
       
   194         """
       
   195         root_elem = ElementTree.fromstring(confml_file_data)
       
   196         
       
   197         # Make sure that we have a ConfML file
       
   198         self.assertTrue(
       
   199             root_elem.tag in ("{http://www.s60.com/xml/confml/1}configuration", "{http://www.s60.com/xml/confml/2}configuration"),
       
   200             "The root element is not a ConfML configuration element (tag is '%s')" % root_elem.tag)
       
   201         
       
   202         # Read the xi:include list
       
   203         result = []
       
   204         for elem in root_elem.findall("{http://www.w3.org/2001/XInclude}include"):
       
   205             result.append(elem.get("href"))
       
   206         
       
   207         return result
       
   208 
       
   209 # =============================================================================
       
   210 
       
   211 def run_in_workdir(workdir):
       
   212     """
       
   213     Decorator for running asset merge tests in a specific working directory.
       
   214     """
       
   215     workdir_abs = os.path.join(ROOT_PATH, 'temp/merge/assetmerge', workdir)
       
   216     
       
   217     def decorate(testmethod):
       
   218         def run_test(self):
       
   219             assert isinstance(self, TestAssetMerge)
       
   220             
       
   221             # Prepare the working directory
       
   222             workdir = self.prepare_workdir(workdir_abs)
       
   223             
       
   224             # Go into the working directory to run the test
       
   225             orig_workdir = os.getcwd()
       
   226             os.chdir(workdir)
       
   227             try:
       
   228                 # Run the test
       
   229                 testmethod(self)
       
   230             finally:
       
   231                 # Revert back to the original working directory
       
   232                 os.chdir(orig_workdir)
       
   233         return run_test
       
   234     
       
   235     return decorate
       
   236 
       
   237 class TestAssetMerge(BaseTestCase):
       
   238     """
       
   239     Tests for merging an asset (basically a single configuration layer) into
       
   240     a specific layer in an existing project.
       
   241     """
       
   242     TESTDATA_ZIP = os.path.join(ROOT_PATH, 'testdata/merge/assetmerge/data.zip')
       
   243     EXPECTED_ZIP = os.path.join(ROOT_PATH, 'testdata/merge/assetmerge/expected.zip')
       
   244     
       
   245     def prepare_workdir(self, workdir):
       
   246         """
       
   247         Prepare a working directory with all needed test data into
       
   248         the given sub-dir under the temporary directory.
       
   249         @param workdir: Absolute path to the working directory.
       
   250         """
       
   251         assert os.path.isabs(workdir)
       
   252         
       
   253         # Remove the working directory
       
   254         self.remove_if_exists(workdir)
       
   255         
       
   256         # Extract asset merge test data into the working dir
       
   257         unzip_file.unzip_file(self.TESTDATA_ZIP, workdir)
       
   258         
       
   259         # Extract expected data
       
   260         unzip_file.unzip_file(self.EXPECTED_ZIP, os.path.join(workdir, 'expected'))
       
   261         
       
   262         return workdir
       
   263     
       
   264     def assert_is_expected(self, subdir):
       
   265         """
       
   266         Assert that the current main_project is equal to the expected data.
       
   267         """
       
   268         current_dir = os.path.abspath('main_project')
       
   269         expected_dir = os.path.abspath(os.path.join('expected', subdir))
       
   270         self.assert_exists_and_contains_something(expected_dir)
       
   271         self.assert_dir_contents_equal(current_dir, expected_dir, ['.svn', '.metadata'])
       
   272     
       
   273     @run_in_workdir('merge_asset1')
       
   274     def test_merge_asset1(self):
       
   275         self.run_command('%s -p main_project --targetlayer assets/test/root.confml -r asset1_v1 --sourcelayer root.confml' % get_cmd('merge'))
       
   276         self.assert_is_expected('asset1_merged')
       
   277     
       
   278     @run_in_workdir('merge_and_update_asset1')
       
   279     def test_merge_and_update_asset1(self):
       
   280         self.run_command('%s -p main_project --targetlayer assets/test/root.confml -r asset1_v1 --sourcelayer root.confml' % get_cmd('merge'))
       
   281         self.assert_is_expected('asset1_merged')
       
   282         self.run_command('%s -p main_project --targetlayer assets/test/root.confml -r asset1_v2 --sourcelayer root.confml' % get_cmd('merge'))
       
   283         self.assert_is_expected('asset1_merged_and_updated')
       
   284     
       
   285     @run_in_workdir('merge_both')
       
   286     def test_merge_both(self):
       
   287         self.run_command('%s -p main_project --targetlayer assets/test/root.confml -r asset1_v1 --sourcelayer root.confml' % get_cmd('merge'))
       
   288         self.run_command('%s -p main_project --targetlayer assets/test/root.confml -r asset2_v1 --sourcelayer root.confml' % get_cmd('merge'))
       
   289         self.assert_is_expected('both_merged')
       
   290     
       
   291     @run_in_workdir('merge_both_and_update')
       
   292     def test_merge_both_and_update(self):
       
   293         
       
   294         self.run_command('%s -p main_project --targetlayer assets/test/root.confml -r asset1_v1 --sourcelayer root.confml' % get_cmd('merge'))
       
   295         self.run_command('%s -p main_project --targetlayer assets/test/root.confml -r asset2_v1 --sourcelayer root.confml' % get_cmd('merge'))
       
   296         self.assert_is_expected('both_merged')
       
   297         
       
   298         self.run_command('%s -p main_project --targetlayer assets/test/root.confml -r asset1_v2 --sourcelayer root.confml' % get_cmd('merge'))
       
   299         self.run_command('%s -p main_project --targetlayer assets/test/root.confml -r asset2_v2 --sourcelayer root.confml' % get_cmd('merge'))
       
   300         self.assert_is_expected('both_merged_and_updated')
       
   301 
       
   302 class TestMergeInvalidParameters(BaseTestCase):
       
   303     
       
   304     def _run_test(self, args, expected_msg):
       
   305         if not isinstance(args, basestring):
       
   306             args = ' '.join(args)
       
   307         
       
   308         cmd = get_cmd('merge') + ' ' + args
       
   309         # Note: The following run_command() should really expect the
       
   310         #       return code 2, but for some reason when running from the
       
   311         #       standalone test set, the return value is 0 for some cases
       
   312         #       (specifically, the ones that don't use parser.error() to
       
   313         #       exit the program)
       
   314         out = self.run_command(cmd, expected_return_code = None)
       
   315         
       
   316         self.assertTrue(expected_msg in out,
       
   317                         "Expected message '%s' not in output ('%s')" % (expected_msg, out))
       
   318     
       
   319     def test_no_remote(self):
       
   320         self._run_test('', "Remote project must be given")
       
   321     
       
   322     def test_source_root_and_target_layer(self):
       
   323         self._run_test(
       
   324            "-p x --targetlayer t.confml -r y --sourceconfiguration s.confml",
       
   325            "Cannot merge a configuration into a layer!")
       
   326     
       
   327     def test_source_layer_and_target_root(self):
       
   328         self._run_test(
       
   329            "-p x --configuration t.confml -r y --sourcelayer s.confml",
       
   330            "Merging a layer into a configuration is not supported at the moment!")
       
   331     
       
   332     def test_source_layer_and_layer_indices(self):
       
   333         self._run_test(
       
   334             ["-p x --configuration t.confml",
       
   335              "-r y --sourcelayer s.confml",
       
   336              "--layer -1 --layer -2"],
       
   337             "Specifying layer indices using --layer is not supported when using --sourcelayer or --targetlayer!")
       
   338     
       
   339     def test_target_layer_and_layer_indices(self):
       
   340         self._run_test(
       
   341             ["-p x --targetlayer t.confml",
       
   342              "-r y --sourceconfiguration s.confml",
       
   343              "--layer -1 --layer -2"],
       
   344             "Specifying layer indices using --layer is not supported when using --sourcelayer or --targetlayer!")
       
   345     
       
   346     def test_invalid_source_layer(self):
       
   347         source_dir = os.path.join(TEMP_DIR, 'invalid_source_layer/source_proj')
       
   348         target_dir = os.path.join(TEMP_DIR, 'invalid_source_layer/target_proj')
       
   349         self.recreate_dir(source_dir)
       
   350         self.recreate_dir(target_dir)
       
   351         self._run_test('-p "%s" --targetlayer foo/root.confml -r "%s" --sourcelayer foo/bar/root.confml' % (source_dir, target_dir),
       
   352                        "Could not merge: Layer root 'foo/bar/root.confml' not found in source project")
       
   353     
       
   354     def test_invalid_source_config(self):
       
   355         source_dir = os.path.join(TEMP_DIR, 'invalid_source_root/source_proj')
       
   356         target_dir = os.path.join(TEMP_DIR, 'invalid_source_root/target_proj')
       
   357         self.recreate_dir(source_dir)
       
   358         self.recreate_dir(target_dir)
       
   359         self._run_test('-p "%s" -c foo_root.confml -r "%s" --sourceconfiguration foobar_root.confml' % (source_dir, target_dir),
       
   360                        "Could not merge: Configuration root 'foobar_root.confml' not found in source project")
       
   361     
       
   362     def test_invalid_merge_policy(self):
       
   363         self._run_test('-p x -r y --merge-policy foopolicy',
       
   364                        "Invalid merge policy: foopolicy")
       
   365     
       
   366     def test_invalid_source_layer_root(self):
       
   367         self._run_test('-p x -r y --sourcelayer foobar --targetlayer test/foo.confml',
       
   368                        "Source layer root should be a .confml file")
       
   369     
       
   370     def test_invalid_target_layer_root(self):
       
   371         self._run_test('-p x -r y --sourcelayer test/foo.confml --targetlayer foobar',
       
   372                        "Target layer root should be a .confml file")
       
   373 
       
   374 if __name__ == '__main__':
       
   375     unittest.main()