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.
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')
20 sys
.path
.extend([BUILD_TOOLS_DIR
, TOOLS_DIR
])
26 MANIFEST_BASENAME
= 'naclsdk_manifest2.json'
28 # Attribute '' defined outside __init__
29 # pylint: disable=W0201
31 class SdkToolsTestCase(unittest
.TestCase
):
34 self
.server
.Shutdown()
35 oshelpers
.Remove(['-rf', self
.basedir
])
37 def SetupDefault(self
):
38 self
.SetupWithBaseDirPrefix('sdktools')
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
)
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."""
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
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
)
69 def _WriteCacheManifest(self
, manifest
):
70 """Write the manifest at nacl_sdk/sdk_cache.
72 This is useful for faking having installed a bundle.
74 manifest_filename
= os
.path
.join(self
.cache_dir
, MANIFEST_BASENAME
)
75 with
open(manifest_filename
, 'w') as stream
:
76 stream
.write(manifest
.GetDataAsString())
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())
86 def _WriteManifest(self
):
87 with
open(os
.path
.join(self
.basedir
, MANIFEST_BASENAME
), 'w') as stream
:
88 stream
.write(self
.manifest
.GetDataAsString())
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
]
94 cmd
.extend(['-r', str(revision
)])
96 process
= subprocess
.Popen(cmd
, stdout
=subprocess
.PIPE
)
97 _
, _
= process
.communicate()
98 self
.assertEqual(process
.returncode
, 0)
100 def _BuildUpdaterArchive(self
, rel_path
, revision
):
101 """Build a new sdk_tools bundle.
104 rel_path: The relative path to build the updater.
105 revision: The revision number to give to this bundle.
107 A manifest_util.Archive() that points to this new bundle on the local
110 self
._BuildUpdater
(os
.path
.join(self
.basedir
, rel_path
), revision
)
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(
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
123 def _Run(self
, args
, expect_error
=False):
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
]
129 cmd
.extend(['-U', self
.server
.GetURL(MANIFEST_BASENAME
)])
130 process
= subprocess
.Popen(cmd
, stdout
=subprocess
.PIPE
)
131 stdout
, _
= process
.communicate()
133 if ((expect_error
and process
.returncode
== 0) or
134 (not expect_error
and process
.returncode
!= 0)):
135 self
.fail('Error running nacl_sdk:\n"""\n%s\n"""' % stdout
)
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))
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
()
154 class TestBuildUpdater(SdkToolsTestCase
):
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')
164 self
.assertTrue(all(name
.startswith('nacl_sdk')
165 for name
in zip_stream
.namelist()))
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')
174 names
= [m
.name
for m
in tar_stream
.getmembers()]
175 self
.assertTrue('LICENSE' in names
)
176 self
.assertTrue('sdk_update.py' in names
)
181 class TestAutoUpdateSdkTools(SdkToolsTestCase
):
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
)
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
()
200 revision
= self
._RunAndExtractRevision
()
201 self
.assertEqual(revision
, new_revision
)
203 def testManualUpdateIsIgnored(self
):
204 """Test that attempting to manually update sdk_tools is ignored.
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.
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
()
217 sdk_tools_update_dir
= os
.path
.join(self
.basedir
, 'nacl_sdk',
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
))
224 def testHelpCommand(self
):
225 """Running naclsdk with -h should work.
227 This is a regression test for a bug where the auto-updater would remove the
228 sdk_tools directory when running "naclsdk -h".
230 self
._WriteManifest
()
234 class TestAutoUpdateSdkToolsDifferentFilesystem(TestAutoUpdateSdkTools
):
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
='.')
242 if __name__
== '__main__':
243 sys
.exit(unittest
.main())