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