- add sources.
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / build_tools / tests / sdktools_test.py
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 import os
7 import re
8 import subprocess
9 import sys
10 import tarfile
11 import tempfile
12 import test_server
13 import unittest
14 import zipfile
15
16 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
17 BUILD_TOOLS_DIR = os.path.dirname(SCRIPT_DIR)
18 TOOLS_DIR = os.path.join(os.path.dirname(BUILD_TOOLS_DIR), 'tools')
19
20 sys.path.extend([BUILD_TOOLS_DIR, TOOLS_DIR])
21 import getos
22 import manifest_util
23 import oshelpers
24
25
26 MANIFEST_BASENAME = 'naclsdk_manifest2.json'
27
28 # Attribute '' defined outside __init__
29 # pylint: disable=W0201
30
31 class SdkToolsTestCase(unittest.TestCase):
32   def tearDown(self):
33     if self.server:
34       self.server.Shutdown()
35     oshelpers.Remove(['-rf', self.basedir])
36
37   def SetupDefault(self):
38     self.SetupWithBaseDirPrefix('sdktools')
39
40   def SetupWithBaseDirPrefix(self, basedir_prefix, tmpdir=None):
41     self.basedir = tempfile.mkdtemp(prefix=basedir_prefix, dir=tmpdir)
42     self.cache_dir = os.path.join(self.basedir, 'nacl_sdk', 'sdk_cache')
43     # We have to make sure that we build our updaters with a version that is at
44     # least as large as the version in the sdk_tools bundle. If not, update
45     # tests may fail because the "current" version (according to the sdk_cache)
46     # is greater than the version we are attempting to update to.
47     self.current_revision = self._GetSdkToolsBundleRevision()
48     self._BuildUpdater(self.basedir, self.current_revision)
49     self.manifest = self._ReadCacheManifest()
50     self.sdk_tools_bundle = self.manifest.GetBundle('sdk_tools')
51     self.server = test_server.LocalHTTPServer(self.basedir)
52
53   def _GetSdkToolsBundleRevision(self):
54     """Get the sdk_tools bundle revision.
55     We get this from the checked-in path; this is the same file that
56     build_updater uses to specify the current revision of sdk_tools."""
57
58     manifest_filename = os.path.join(BUILD_TOOLS_DIR, 'json',
59                                      'naclsdk_manifest0.json')
60     manifest = manifest_util.SDKManifest()
61     manifest.LoadDataFromString(open(manifest_filename, 'r').read())
62     return manifest.GetBundle('sdk_tools').revision
63
64   def _WriteConfig(self, config_data):
65     config_filename = os.path.join(self.cache_dir, 'naclsdk_config.json')
66     with open(config_filename, 'w') as stream:
67       stream.write(config_data)
68
69   def _WriteCacheManifest(self, manifest):
70     """Write the manifest at nacl_sdk/sdk_cache.
71
72     This is useful for faking having installed a bundle.
73     """
74     manifest_filename = os.path.join(self.cache_dir, MANIFEST_BASENAME)
75     with open(manifest_filename, 'w') as stream:
76       stream.write(manifest.GetDataAsString())
77
78   def _ReadCacheManifest(self):
79     """Read the manifest at nacl_sdk/sdk_cache."""
80     manifest_filename = os.path.join(self.cache_dir, MANIFEST_BASENAME)
81     manifest = manifest_util.SDKManifest()
82     with open(manifest_filename) as stream:
83       manifest.LoadDataFromString(stream.read())
84     return manifest
85
86   def _WriteManifest(self):
87     with open(os.path.join(self.basedir, MANIFEST_BASENAME), 'w') as stream:
88       stream.write(self.manifest.GetDataAsString())
89
90   def _BuildUpdater(self, out_dir, revision=None):
91     build_updater_py = os.path.join(BUILD_TOOLS_DIR, 'build_updater.py')
92     cmd = [sys.executable, build_updater_py, '-o', out_dir]
93     if revision:
94       cmd.extend(['-r', str(revision)])
95
96     process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
97     _, _ = process.communicate()
98     self.assertEqual(process.returncode, 0)
99
100   def _BuildUpdaterArchive(self, rel_path, revision):
101     """Build a new sdk_tools bundle.
102
103     Args:
104       rel_path: The relative path to build the updater.
105       revision: The revision number to give to this bundle.
106     Returns:
107       A manifest_util.Archive() that points to this new bundle on the local
108       server.
109     """
110     self._BuildUpdater(os.path.join(self.basedir, rel_path), revision)
111
112     new_sdk_tools_tgz = os.path.join(self.basedir, rel_path, 'sdk_tools.tgz')
113     with open(new_sdk_tools_tgz, 'rb') as sdk_tools_stream:
114       archive_sha1, archive_size = manifest_util.DownloadAndComputeHash(
115           sdk_tools_stream)
116
117     archive = manifest_util.Archive('all')
118     archive.url = self.server.GetURL('%s/sdk_tools.tgz' % (rel_path,))
119     archive.checksum = archive_sha1
120     archive.size = archive_size
121     return archive
122
123   def _Run(self, args):
124     naclsdk_shell_script = os.path.join(self.basedir, 'nacl_sdk', 'naclsdk')
125     if getos.GetPlatform() == 'win':
126       naclsdk_shell_script += '.bat'
127     cmd = [naclsdk_shell_script]
128     cmd.extend(args)
129     cmd.extend(['-U', self.server.GetURL(MANIFEST_BASENAME)])
130     process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
131     stdout, _ = process.communicate()
132     try:
133       self.assertEqual(process.returncode, 0)
134     except Exception:
135       print stdout
136       raise
137     return stdout
138
139   def _RunAndExtractRevision(self):
140     stdout = self._Run(['version'])
141     match = re.search('version r(\d+)', stdout)
142     self.assertTrue(match is not None)
143     return int(match.group(1))
144
145
146 class TestSdkTools(SdkToolsTestCase):
147   def testPathHasSpaces(self):
148     """Test that running naclsdk from a path with spaces works."""
149     self.SetupWithBaseDirPrefix('sdk tools')
150     self._WriteManifest()
151     self._RunAndExtractRevision()
152
153
154 class TestBuildUpdater(SdkToolsTestCase):
155   def setUp(self):
156     self.SetupDefault()
157
158   def testUpdaterPathsAreSane(self):
159     """Test that the paths to files in nacl_sdk.zip and sdktools.tgz are
160     relative to the output directory."""
161     nacl_sdk_zip_path = os.path.join(self.basedir, 'nacl_sdk.zip')
162     zip_stream = zipfile.ZipFile(nacl_sdk_zip_path, 'r')
163     try:
164       self.assertTrue(all(name.startswith('nacl_sdk')
165                           for name in zip_stream.namelist()))
166     finally:
167       zip_stream.close()
168
169     # sdktools.tgz has no built-in directories to look for. Instead, just look
170     # for some files that must be there.
171     sdktools_tgz_path = os.path.join(self.basedir, 'sdk_tools.tgz')
172     tar_stream = tarfile.open(sdktools_tgz_path, 'r:gz')
173     try:
174       names = [m.name for m in tar_stream.getmembers()]
175       self.assertTrue('LICENSE' in names)
176       self.assertTrue('sdk_update.py' in names)
177     finally:
178       tar_stream.close()
179
180
181 class TestAutoUpdateSdkTools(SdkToolsTestCase):
182   def setUp(self):
183     self.SetupDefault()
184
185   def testNoUpdate(self):
186     """Test that running naclsdk with current revision does nothing."""
187     self._WriteManifest()
188     revision = self._RunAndExtractRevision()
189     self.assertEqual(revision, self.current_revision)
190
191   def testUpdate(self):
192     """Test that running naclsdk with a new revision will auto-update."""
193     new_revision = self.current_revision + 1
194     archive = self._BuildUpdaterArchive('new', new_revision)
195     self.sdk_tools_bundle.RemoveAllArchivesForHostOS(archive.host_os)
196     self.sdk_tools_bundle.AddArchive(archive)
197     self.sdk_tools_bundle.revision = new_revision
198     self._WriteManifest()
199
200     revision = self._RunAndExtractRevision()
201     self.assertEqual(revision, new_revision)
202
203   def testManualUpdateIsIgnored(self):
204     """Test that attempting to manually update sdk_tools is ignored.
205
206     If the sdk_tools bundle was updated normally (i.e. the old way), it would
207     leave a sdk_tools_update folder that would then be copied over on a
208     subsequent run. This test ensures that there is no folder made.
209     """
210     new_revision = self.current_revision + 1
211     archive = self._BuildUpdaterArchive('new', new_revision)
212     self.sdk_tools_bundle.RemoveAllArchivesForHostOS(archive.host_os)
213     self.sdk_tools_bundle.AddArchive(archive)
214     self.sdk_tools_bundle.revision = new_revision
215     self._WriteManifest()
216
217     sdk_tools_update_dir = os.path.join(self.basedir, 'nacl_sdk',
218         'sdk_tools_update')
219     self.assertFalse(os.path.exists(sdk_tools_update_dir))
220     stdout = self._Run(['update', 'sdk_tools'])
221     self.assertTrue(stdout.find('Ignoring manual update request.') != -1)
222     self.assertFalse(os.path.exists(sdk_tools_update_dir))
223
224   def testHelpCommand(self):
225     """Running naclsdk with -h should work.
226
227     This is a regression test for a bug where the auto-updater would remove the
228     sdk_tools directory when running "naclsdk -h".
229     """
230     self._WriteManifest()
231     self._Run(['-h'])
232
233
234 class TestAutoUpdateSdkToolsDifferentFilesystem(TestAutoUpdateSdkTools):
235   def setUp(self):
236     # On Linux (on my machine at least), /tmp is a different filesystem than
237     # the current directory. os.rename fails when the source and destination
238     # are on different filesystems. Test that case here.
239     self.SetupWithBaseDirPrefix('sdktools', tmpdir='.')
240
241
242 if __name__ == '__main__':
243   sys.exit(unittest.main())