|
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() |