Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(180)

Side by Side Diff: functional/nacl_sdk.py

Issue 10024031: Nacl sdk automated test(method-testNaClSDK) of new installation process of NaCl sdk. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/chrome/test/
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 import copy 6 import copy
7 import ctypes 7 import ctypes
8 from distutils import version 8 from distutils import version
9 import fnmatch 9 import fnmatch
10 import glob 10 import glob
11 import hashlib 11 import hashlib
12 import logging 12 import logging
13 import os 13 import os
14 import platform 14 import platform
15 import shutil 15 import shutil
16 import subprocess 16 import subprocess
17 import sys 17 import sys
18 import tarfile
19 import tempfile 18 import tempfile
20 import urllib2 19 import urllib2
21 import xml.dom.minidom 20 import xml.dom.minidom
21 import zipfile
22 import re
22 23
23 import pyauto_functional # Must be imported before pyauto. 24 import pyauto_functional # Must be imported before pyauto.
24 import pyauto 25 import pyauto
25 import pyauto_utils 26 import pyauto_utils
26 27 import time
chrisphan 2012/04/23 02:03:37 Move this import up along with other python lib im
Pooja Nihalani 2012/04/23 21:23:54 Done.
27 28
28 class NaClSDKTest(pyauto.PyUITest): 29 class NaClSDKTest(pyauto.PyUITest):
29 """Tests for the NaCl SDK.""" 30 """Tests for the NaCl SDK."""
30 _extracted_sdk_path = None 31 _extracted_sdk_path = None
31 _temp_dir = None 32 _temp_dir = None
33 _pepper_versions = []
34 _updated_pepper_versions = []
35 _latest_updated_pepper_versions = []
32 _settings = { 36 _settings = {
33 'release_win_sdk_url': 'http://commondatastorage.googleapis.com/'
34 'nativeclient-mirror/nacl/nacl_sdk/staging/naclsdk_win.exe',
35 'release_mac_sdk_url': 'http://commondatastorage.googleapis.com/'
36 'nativeclient-mirror/nacl/nacl_sdk/staging/naclsdk_mac.tgz',
37 'release_lin_sdk_url': 'http://commondatastorage.googleapis.com/'
38 'nativeclient-mirror/nacl/nacl_sdk/staging/naclsdk_linux.tgz',
39 'expected_md5_url': 'http://commondatastorage.googleapis.com/'
40 'nativeclient-mirror',
41 'release_win_expected_md5_key': 'nacl/nacl_sdk/staging/naclsdk_win.exe',
42 'release_mac_expected_md5_key': 'nacl/nacl_sdk/staging/naclsdk_mac.tgz',
43 'release_lin_expected_md5_key': 'nacl/nacl_sdk/staging/'
44 'naclsdk_linux.tgz',
45 'post_sdk_download_url': 'http://code.google.com/chrome/nativeclient/' 37 'post_sdk_download_url': 'http://code.google.com/chrome/nativeclient/'
46 'docs/download.html', 38 'docs/download.html',
47 'post_win_sdk_url': 'http://commondatastorage.googleapis.com/' 39 'post_sdk_url': 'http://commondatastorage.googleapis.com/'
48 'nativeclient-mirror/nacl/nacl_sdk/naclsdk_win.exe', 40 'nativeclient-mirror/nacl/nacl_sdk/nacl_sdk.zip',
49 'post_mac_sdk_url': 'http://commondatastorage.googleapis.com/'
50 'nativeclient-mirror/nacl/nacl_sdk/naclsdk_mac.tgz',
51 'post_lin_sdk_url': 'http://commondatastorage.googleapis.com/'
52 'nativeclient-mirror/nacl/nacl_sdk/naclsdk_linux.tgz',
53 'min_required_chrome_build': 14, 41 'min_required_chrome_build': 14,
54 'gallery_examples': {
55 'life': 'http://nacl-gallery.appspot.com/life/life.html',
56 'hello_world': 'http://nacl-gallery.appspot.com/hello_world/'
57 'hello_world.html',
58 'pi_generator': 'http://nacl-gallery.appspot.com/pi_generator/'
59 'pi_generator.html',
60 'sine_synth': 'http://nacl-gallery.appspot.com/sine_synth/'
61 'sine_synth.html'
62 },
63 'prerelease_gallery': {
64 'hello_world': 'http://4.nacl-gallery.appspot.com/hello_world/'
65 'hello_world.html',
66 'hello_world_c': 'http://4.nacl-gallery.appspot.com/hello_world_c/'
67 'hello_world.html',
68 'life': 'http://4.nacl-gallery.appspot.com/life/life.html',
69 'pi_generator': 'http://4.nacl-gallery.appspot.com/pi_generator/'
70 'pi_generator.html',
71 'sine_synth': 'http://4.nacl-gallery.appspot.com/sine_synth/'
72 'sine_synth.html',
73 'geturl': 'http://4.nacl-gallery.appspot.com/geturl/geturl.html'
74 }
75 } 42 }
76 43
77 def tearDown(self): 44 def tearDown(self):
78 pyauto.PyUITest.tearDown(self) 45 pyauto.PyUITest.tearDown(self)
79 self._RemoveDownloadedTestFile() 46 self._RemoveDownloadedTestFile()
80 47
81 def testNaClSDK(self): 48 def testNaClSDK(self):
82 """Verify that NaCl SDK is working properly.""" 49 """Verify that NaCl SDK is working properly."""
83 if not self._HasAllSystemRequirements(): 50 if not self._HasAllSystemRequirements():
84 logging.info('System does not meet the requirements.') 51 logging.info('System does not meet the requirements.')
85 return 52 return
86 self._extracted_sdk_path = tempfile.mkdtemp() 53 self._extracted_sdk_path = tempfile.mkdtemp()
87
88 self._VerifyDownloadLinks() 54 self._VerifyDownloadLinks()
89 self._VerifyNaClSDKInstaller() 55 self._VerifyNaClSDKInstaller()
90 self._VerifyBuildStubProject() 56 self._Verifyinstall()
57 self._Verifyupdate()
91 self._LaunchServerAndVerifyExamples() 58 self._LaunchServerAndVerifyExamples()
92 self._VerifyRebuildExamples()
93 self._VerifySelldrAndNcval()
94
95 def testVerifyNaClSDKChecksum(self):
96 """Verify NaCl SDK Checksum."""
97 if not self._HasAllSystemRequirements():
98 logging.info('System does not meet the requirements.')
99 return
100
101 self._DownloadNaClSDK()
102
103 if pyauto.PyUITest.IsWin():
104 expected_md5_key = self._settings['release_win_expected_md5_key']
105 file_path = os.path.join(self._temp_dir, 'naclsdk_win.exe')
106 elif pyauto.PyUITest.IsMac():
107 expected_md5_key = self._settings['release_mac_expected_md5_key']
108 file_path = os.path.join(self._temp_dir, 'naclsdk_mac.tgz')
109 elif pyauto.PyUITest.IsLinux():
110 expected_md5_key = self._settings['release_lin_expected_md5_key']
111 file_path = os.path.join(self._temp_dir, 'naclsdk_linux.tgz')
112 else:
113 self.fail(msg='NaCl SDK does not support this OS.')
114
115 # Get expected MD5.
116 expected_md5_url = self._settings['expected_md5_url']
117 response = urllib2.urlopen(expected_md5_url)
118 dom = xml.dom.minidom.parseString(response.read())
119 dom_content = dom.getElementsByTagName('Contents')
120 expected_md5 = None
121 for con in dom_content:
122 if (self._GetXMLNodeData(con.getElementsByTagName('Key')[0].childNodes)
123 == expected_md5_key):
124 node = con.getElementsByTagName('ETag')[0].childNodes
125 expected_md5 = self._GetXMLNodeData(node).strip('"')
126 self.assertTrue(expected_md5,
127 msg='Cannot get expected MD5 from %s.' % expected_md5_url)
128
129 md5 = hashlib.md5()
130 md5.update(open(file_path).read())
131 md5_sum = md5.hexdigest()
132 self.assertEqual(expected_md5, md5_sum,
133 msg='Unexpected checksum. Expected: %s, got: %s'
134 % (expected_md5, md5_sum))
135
136 def testVerifyNaClPlugin(self):
137 """Verify NaCl plugin."""
138 if not self._HasAllSystemRequirements():
139 logging.info('System does not meet the requirements.')
140 return
141 self._OpenExamplesAndStartTest(
142 self._settings['gallery_examples'])
143
144 def testVerifyPrereleaseGallery(self):
145 """Verify Pre-release gallery examples."""
146 if not self._HasAllSystemRequirements():
147 logging.info('System does not meet the requirements.')
148 return
149 self._OpenExamplesAndStartTest(
150 self._settings['prerelease_gallery'])
151 59
152 def _VerifyDownloadLinks(self): 60 def _VerifyDownloadLinks(self):
153 """Verify the download links.""" 61 """Verify the download links.
62
63 Simply verify that NaCl download links exist in html page.
64 """
154 html = None 65 html = None
155 for i in xrange(3): 66 for i in xrange(3):
156 try: 67 try:
157 html = urllib2.urlopen(self._settings['post_sdk_download_url']).read() 68 html = urllib2.urlopen(self._settings['post_sdk_download_url']).read()
158 break 69 break
159 except: 70 except:
160 pass 71 pass
161 self.assertTrue(html, 72 self.assertTrue(html,
162 msg='Cannot open URL: %s' % 73 msg = 'Cannot open URL: %s' %
chrisphan 2012/04/23 02:03:37 Remove spaces for keyword arguments. Repeat every
Pooja Nihalani 2012/04/23 21:23:54 Done.
163 self._settings['post_sdk_download_url']) 74 self._settings['post_sdk_download_url'])
164 75 sdk_url = self._settings['post_sdk_url']
165 # Make sure the correct URL is under the correct label. 76 url_index = html.find(sdk_url)
166 if pyauto.PyUITest.IsWin(): 77 self.assertTrue(url_index > -1,
167 win_sdk_url = self._settings['post_win_sdk_url'] 78 msg = 'Missing SDK download URL: %s' % sdk_url)
168 win_url_index = html.find(win_sdk_url)
169 self.assertTrue(win_url_index > -1,
170 msg='Missing SDK download URL: %s' % win_sdk_url)
171 win_keyword_index = html.rfind('Windows', 0, win_url_index)
172 self.assertTrue(win_keyword_index > -1,
173 msg='Misplaced download link: %s' % win_sdk_url)
174 elif pyauto.PyUITest.IsMac():
175 mac_sdk_url = self._settings['post_mac_sdk_url']
176 mac_url_index = html.find(mac_sdk_url)
177 self.assertTrue(mac_url_index > -1,
178 msg='Missing SDK download URL: %s' % mac_sdk_url)
179 mac_keyword_index = html.rfind('Macintosh', 0, mac_url_index)
180 self.assertTrue(mac_keyword_index > -1,
181 msg='Misplaced download link: %s' % mac_sdk_url)
182 elif pyauto.PyUITest.IsLinux():
183 lin_sdk_url = self._settings['post_lin_sdk_url']
184 lin_url_index = html.find(lin_sdk_url)
185 self.assertTrue(lin_url_index > -1,
186 msg='Missing SDK download URL: %s' % lin_sdk_url)
187 lin_keyword_index = html.rfind('Linux', 0, lin_url_index)
188 self.assertTrue(lin_keyword_index > -1,
189 msg='Misplaced download link: %s' % lin_sdk_url)
190 else:
191 self.fail(msg='NaCl SDK does not support this OS.')
192 79
193 def _VerifyNaClSDKInstaller(self): 80 def _VerifyNaClSDKInstaller(self):
194 """Verify NaCl SDK installer.""" 81 """Verify NaCl SDK installer."""
195 search_list = [ 82 search_list = [
196 'build.scons', 83 'sdk_cache/',
197 'favicon.ico', 84 'sdk_tools/',
198 'geturl/',
199 'hello_world/',
200 'hello_world_c/',
201 'httpd.py',
202 'index.html',
203 'nacl_sdk_scons/',
204 'pi_generator/',
205 'scons',
206 'sine_synth/'
207 ] 85 ]
chrisphan 2012/04/23 02:03:37 Are these the only items you need to verify exist?
Pooja Nihalani 2012/04/23 21:23:54 Yes, these are the only items in that folder which
86 mac_lin_additional_search_items = [
87 'naclsdk',
88 ]
89 win_additional_search_items = [
90 'naclsdk.bat'
91 ]
92 self._DownloadNaClSDK()
93 self._ExtractNaClSDK()
94 if pyauto.PyUITest.IsWin():
95 self._SearchNaClSDKFile(
96 search_list + win_additional_search_items)
97 elif pyauto.PyUITest.IsMac() or pyauto.PyUITest.IsLinux():
98 self._SearchNaClSDKFile(
99 search_list + mac_lin_additional_search_items)
100 else:
101 self.fail(msg = 'NaCl SDK does not support this OS.')
208 102
209 mac_lin_additional_search_items = [ 103 def _Verifyinstall(self):
chrisphan 2012/04/23 02:03:37 _VerifyInstall
Pooja Nihalani 2012/04/23 21:23:54 Done.
210 'sel_ldr_x86_32', 104 """Verify installation of NACL sdk."""
211 'sel_ldr_x86_64', 105 # Executing naclsdk(.bat) list
212 'ncval_x86_32', 106 if pyauto.PyUITest.IsWin():
213 'ncval_x86_64' 107 source_file = os.path.join(
214 ] 108 self._extracted_sdk_path+'\\nacl_sdk', 'naclsdk.bat')
chrisphan 2012/04/23 02:03:37 Remove string cat in path join. Do same for every
Pooja Nihalani 2012/04/23 21:23:54 Done.
109 elif pyauto.PyUITest.IsMac() or pyauto.PyUITest.IsLinux():
110 source_file = os.path.join(
111 self._extracted_sdk_path+'//nacl_sdk', 'naclsdk')
112 process_chmod = subprocess.call(['chmod', '-R', '755',
chrisphan 2012/04/23 02:03:37 You can remove 'process_chmod' var if ur not using
Pooja Nihalani 2012/04/23 21:23:54 Done.
113 self._extracted_sdk_path])
114 else:
115 self.fail(msg = 'NaCl SDK does not support this OS.')
116 output, error = subprocess.Popen([source_file, 'list'],
117 stdout = subprocess.PIPE,
118 stderr= subprocess.PIPE).communicate()
215 119
216 win_additional_search_items = [ 120 def _Verifyupdate(self):
chrisphan 2012/04/23 02:03:37 _VerifyUpdate
Pooja Nihalani 2012/04/23 21:23:54 Done.
217 'httpd.cmd', 121 """Verify update of NACL sdk"""
218 'sel_ldr_x86_32.exe', 122 # Executing naclsdk(.bat) update
219 'sel_ldr_x86_64.exe',
220 'ncval_x86_32.exe',
221 'ncval_x86_64.exe'
222 ]
223
224 self._DownloadNaClSDK()
225
226 if pyauto.PyUITest.IsWin(): 123 if pyauto.PyUITest.IsWin():
227 self._ExtractNaClSDK() 124 source_file = os.path.join(self._extracted_sdk_path+'\\nacl_sdk',
228 self._SearchNaClSDKFileWindows( 125 'naclsdk.bat')
229 search_list + win_additional_search_items) 126 elif pyauto.PyUITest.IsMac() or pyauto.PyUITest.IsLinux():
230 elif pyauto.PyUITest.IsMac(): 127 source_file = os.path.join(self._extracted_sdk_path+'//nacl_sdk',
231 source_file = os.path.join(self._temp_dir, 'naclsdk_mac.tgz') 128 'naclsdk')
232 self._SearchNaClSDKTarFile(search_list + mac_lin_additional_search_items,
233 source_file)
234 self._ExtractNaClSDK()
235 elif pyauto.PyUITest.IsLinux():
236 source_file = os.path.join(self._temp_dir, 'naclsdk_linux.tgz')
237 self._SearchNaClSDKTarFile(search_list + mac_lin_additional_search_items,
238 source_file)
239 self._ExtractNaClSDK()
240 else: 129 else:
241 self.fail(msg='NaCl SDK does not support this OS.') 130 self.fail(msg = 'NaCl SDK does not support this OS.')
242 131 updated_output, error = subprocess.Popen(
chrisphan 2012/04/23 02:03:37 Comment here what you're doing.
Pooja Nihalani 2012/04/23 21:23:54 Done.
243 def _VerifyBuildStubProject(self): 132 [source_file, 'update'],
244 """Build stub project.""" 133 stdout = subprocess.PIPE, stderr = subprocess.PIPE).communicate()
245 stub_project_files = [ 134 self._updated_pepper_versions.extend(
246 'build.scons', 135 re.findall('Updating bundle (pepper_[0-9]{2})', updated_output))
247 'scons' 136 self._updated_pepper_versions = list(set(self._updated_pepper_versions))
248 ] 137 self._updated_pepper_versions.sort(key = str.lower)
249 project_template_path = self._GetDirectoryPath('project_templates', 138 updated_pepper_versions_len = len(self._updated_pepper_versions)
250 self._extracted_sdk_path) 139 self._latest_updated_pepper_versions = filter(
251 examples_path = self._GetDirectoryPath('examples', 140 lambda x:x>='pepper_18', self._updated_pepper_versions)
chrisphan 2012/04/23 02:03:37 Add a TODO here to resolve this constant value.
Pooja Nihalani 2012/04/23 21:23:54 Done.
252 self._extracted_sdk_path)
253 init_project_path = os.path.join(project_template_path, 'init_project.py')
254
255 # Build a C project.
256 subprocess.call(
257 ['python', init_project_path, '-n', 'hello_c', '-c', '-d',
258 examples_path], stdout=subprocess.PIPE)
259
260 hello_c_path = os.path.join(examples_path, 'hello_c')
261 for file in stub_project_files:
262 self.assertTrue(self._HasFile(file, hello_c_path),
263 msg='Cannot build C stub project.')
264
265 # Build a C++ project.
266 subprocess.call(
267 ['python', init_project_path, '-n', 'hello_cc', '-d',
268 examples_path], stdout=subprocess.PIPE)
269
270 hello_cc_path = os.path.join(examples_path, 'hello_cc')
271 for file in stub_project_files:
272 self.assertTrue(self._HasFile(file, hello_cc_path),
273 msg='Cannot build C++ stub project.')
274 141
275 def _LaunchServerAndVerifyExamples(self): 142 def _LaunchServerAndVerifyExamples(self):
276 """Start local HTTP server and verify examples.""" 143 """Start local HTTP server and verify examples."""
277 # Make sure server is not open. 144 if pyauto.PyUITest.IsWin():
145 examples_path = os.path.join(self._extracted_sdk_path + '\\nacl_sdk\\' +
chrisphan 2012/04/23 02:03:37 Line up params.
Pooja Nihalani 2012/04/23 21:23:54 Done.
146 self._latest_updated_pepper_versions[0],
147 'examples')
148 elif pyauto.PyUITest.IsMac() or pyauto.PyUITest.IsLinux():
149 examples_path = os.path.join(self._extracted_sdk_path + '//nacl_sdk//' +
150 self._latest_updated_pepper_versions[0],
chrisphan 2012/04/23 02:03:37 Line up params.
Pooja Nihalani 2012/04/23 21:23:54 Done.
151 'examples')
152 else:
153 self.fail(msg = 'NaCl SDK does not support this OS.')
154
155 # Close server if it's already open.
278 if self._IsURLAlive('http://localhost:5103'): 156 if self._IsURLAlive('http://localhost:5103'):
279 self._CloseHTTPServer() 157 self._CloseHTTPServer()
280 158
281 # Start HTTP server. 159 # Launch local http server.
282 examples_path = self._GetDirectoryPath('examples', 160 os.chdir(examples_path)
283 self._extracted_sdk_path) 161 proc = subprocess.Popen(['make RUN'], shell = True)
284 if pyauto.PyUITest.IsWin():
285 http_path = os.path.join(examples_path, 'httpd.cmd')
286 proc = subprocess.Popen([http_path], cwd=examples_path)
287 else:
288 http_path = os.path.join(examples_path, 'httpd.py')
289 proc = subprocess.Popen(['python', http_path], cwd=examples_path)
290
291 success = self.WaitUntil( 162 success = self.WaitUntil(
292 lambda: self._IsURLAlive('http://localhost:5103'), 163 lambda: self._IsURLAlive('http://localhost:5103'),
293 timeout=30, retry_sleep=1, expect_retval=True) 164 timeout = 150, retry_sleep = 1, expect_retval = True)
chrisphan 2012/04/23 02:03:37 Do you need timeout to be this long? Default is 3
Pooja Nihalani 2012/04/23 21:23:54 Yes, it other wise crashes on windows.. On 2012/0
294 self.assertTrue(success, 165
295 msg='Cannot open HTTP server. %s' %
296 self.GetActiveTabTitle())
297
298 examples = { 166 examples = {
299 'hello_world_c': 'http://localhost:5103/hello_world_c/'
300 'hello_world.html',
301 'hello_world': 'http://localhost:5103/hello_world/hello_world.html',
302 'geturl': 'http://localhost:5103/geturl/geturl.html', 167 'geturl': 'http://localhost:5103/geturl/geturl.html',
303 'pi_generator': 'http://localhost:5103/pi_generator/pi_generator.html', 168 'pi_generator': 'http://localhost:5103/pi_generator/pi_generator.html',
304 'sine_synth': 'http://localhost:5103/sine_synth/sine_synth.html', 169 'sine_synth': 'http://localhost:5103/sine_synth/sine_synth.html',
170 'input_events': 'http://localhost:5103/input_events/input_events.html',
171 'dynamic_library_open': 'http://localhost:5103/dlopen/dlopen.html',
172 'load_progress':
173 'http://localhost:5103/load_progress/load_progress.html',
174 'multithreaded_input_events':
175 'http://localhost:5103/multithreaded_input_events/mt_input_events.html',
176 'web_socket':'http://localhost:5103/websocket/websocket.html',
305 } 177 }
306 try: 178 try:
307 self._OpenExamplesAndStartTest(examples) 179 self._OpenExamplesAndStartTest(examples)
308 finally: 180 finally:
309 self._CloseHTTPServer(proc) 181 self._CloseHTTPServer(proc)
310 182
311 def _VerifyRebuildExamples(self):
312 """Re-build the examples and verify they are as expected."""
313 example_dirs = [
314 'geturl',
315 'hello_world',
316 'hello_world_c',
317 'pi_generator',
318 'sine_synth'
319 ]
320 examples_path = self._GetDirectoryPath('examples',
321 self._extracted_sdk_path)
322
323 scons_path = os.path.join(examples_path, 'scons -c')
324 subprocess.call([scons_path], cwd=examples_path, shell=True)
325 for x in example_dirs:
326 ex_path = os.path.join(examples_path, x)
327 self.assertFalse(self._HasFile('*.nmf', ex_path),
328 msg='Failed running scons -c.')
329
330 scons_path = os.path.join(examples_path, 'scons')
331 proc = subprocess.Popen([scons_path], cwd=examples_path,
332 stdout=subprocess.PIPE, shell=True)
333 proc.communicate()
334
335 # Verify each example directory contains .nmf file.
336 for dir in example_dirs:
337 dir = os.path.join(examples_path, dir)
338 if not self._HasFile('*.nmf', dir):
339 self.fail(msg='Failed running scons.')
340
341 self._LaunchServerAndVerifyExamples()
342
343 def _VerifySelldrAndNcval(self):
344 """Verify sel_ldr and ncval."""
345 architecture = self._GetPlatformArchitecture()
346 scons_arg = None
347 if pyauto.PyUITest.IsWin():
348 if architecture == '64bit':
349 scons_arg = 'test64'
350 else:
351 scons_arg = 'test32'
352 elif pyauto.PyUITest.IsMac():
353 scons_arg = 'test64'
354 elif pyauto.PyUITest.IsLinux():
355 scons_arg = 'test64'
356
357 examples_path = self._GetDirectoryPath('examples',
358 self._extracted_sdk_path)
359 scons_path = os.path.join(examples_path, 'scons ' + scons_arg)
360
361 # Build and run the unit test.
362 proc = subprocess.Popen([scons_path], stdout=subprocess.PIPE,
363 shell=True, cwd=examples_path)
364 lines = proc.communicate()[0].splitlines()
365 test_ran = False
366
367 for line in lines:
368 if 'Check:' in line:
369 self.assertTrue('passed' in line,
370 msg='Nacl-sel_ldr unit test failed.')
371 test_ran = True
372 self.assertTrue(test_ran,
373 msg='Failed to build and run nacl-sel_ldr unit test.')
374
375 if architecture == '64bit':
376 self.assertTrue(
377 self._HasPathInTree('hello_world_x86_64.nexe',
378 True, root=examples_path),
379 msg='Missing file: hello_world_x86_64.nexe.')
380 else:
381 self.assertTrue(
382 self._HasPathInTree('hello_world_x86_32.nexe',
383 True, root=examples_path),
384 msg='Missing file: hello_world_x86_32.nexe.')
385
386 # Verify that a mismatch of sel_ldr and .nexe produces an error.
387 toolchain_path = self._GetDirectoryPath('toolchain',
388 self._extracted_sdk_path)
389 bin_path = self._GetDirectoryPath('bin', toolchain_path)
390 hello_world_path = self._GetDirectoryPath('hello_world', examples_path)
391 sel_32_path = os.path.join(bin_path, 'sel_ldr_x86_32')
392 sel_64_path = os.path.join(bin_path, 'sel_ldr_x86_64')
393 nexe_32_path = os.path.join(hello_world_path, 'hello_world_x86_32.nexe')
394 nexe_64_path = os.path.join(hello_world_path, 'hello_world_x86_64.nexe')
395
396 if architecture == '64bit':
397 success = self._RunProcessAndCheckOutput(
398 [sel_64_path, nexe_32_path], 'Error while loading')
399 else:
400 success = self._RunProcessAndCheckOutput(
401 [sel_32_path, nexe_64_path], 'Error while loading')
402 self.assertTrue(success,
403 msg='Failed to verify sel_ldr and .nexe mismatch.')
404
405 # Run the appropriate ncval for the platform on the matching .nexe.
406 ncval_32_path = os.path.join(bin_path, 'ncval_x86_32')
407 ncval_64_path = os.path.join(bin_path, 'ncval_x86_64')
408
409 if architecture == '64bit':
410 success = self._RunProcessAndCheckOutput(
411 [ncval_64_path, nexe_64_path], 'is safe')
412 else:
413 success = self._RunProcessAndCheckOutput(
414 [ncval_32_path, nexe_32_path], 'is safe')
415 self.assertTrue(success, msg='Failed to verify ncval.')
416
417 # Verify that a mismatch of ncval and .nexe produces an error.
418 if architecture == '64bit':
419 success = self._RunProcessAndCheckOutput(
420 [ncval_64_path, nexe_32_path], 'is safe', is_in=False)
421 else:
422 success = self._RunProcessAndCheckOutput(
423 [ncval_32_path, nexe_64_path], 'is safe', is_in=False)
424 self.assertTrue(success, msg='Failed to verify ncval and .nexe mismatch.')
425
426 def _RemoveDownloadedTestFile(self): 183 def _RemoveDownloadedTestFile(self):
427 """Delete downloaded files and dirs from downloads directory.""" 184 """Delete downloaded files and dirs from downloads directory."""
185 if pyauto.PyUITest.IsWin():
186 os.chdir(self._extracted_sdk_path+'.\..')
chrisphan 2012/04/23 02:03:37 Use os.path.join. Same for everywhere else.
Pooja Nihalani 2012/04/23 21:23:54 Do you want me to use os.path.join and then do a c
chrisphan 2012/04/24 01:22:04 Yes, that is possible.
187 elif pyauto.PyUITest.IsMac():
188 os.chdir(self._extracted_sdk_path+'/../')
189 elif pyauto.PyUITest.IsLinux():
190 os.chdir(self._extracted_sdk_path+'/../')
191 else:
192 self.fail(msg = 'NaCl SDK does not support this OS.')
193
428 if self._extracted_sdk_path and os.path.exists(self._extracted_sdk_path): 194 if self._extracted_sdk_path and os.path.exists(self._extracted_sdk_path):
429 self._CloseHTTPServer() 195 self._CloseHTTPServer()
430 196
431 def _RemoveFile(): 197 def _RemoveFile():
432 shutil.rmtree(self._extracted_sdk_path, ignore_errors=True) 198 shutil.rmtree(self._extracted_sdk_path, ignore_errors = True)
433 return os.path.exists(self._extracted_sdk_path) 199 return os.path.exists(self._extracted_sdk_path)
434 200
435 success = self.WaitUntil(_RemoveFile, retry_sleep=2, expect_retval=False) 201 success = self.WaitUntil(_RemoveFile, retry_sleep=20,
chrisphan 2012/04/23 02:03:37 'retry_sleep' here is too long. The default 'time
Pooja Nihalani 2012/04/23 21:23:54 Done.
202 expect_retval = False)
436 self.assertTrue(success, 203 self.assertTrue(success,
437 msg='Cannot remove %s' % self._extracted_sdk_path) 204 msg = 'Cannot remove %s' % self._extracted_sdk_path)
438 205
439 if self._temp_dir: 206 if self._temp_dir:
440 pyauto_utils.RemovePath(self._temp_dir) 207 pyauto_utils.RemovePath(self._temp_dir)
441 208
442 def _RunProcessAndCheckOutput(self, args, look_for, is_in=True):
443 """Run process and look for string in output.
444
445 Args:
446 args: Argument strings to pass to subprocess.
447 look_for: The string to search in output.
448 is_in: True if checking if param look_for is in output.
449 False if checking if param look_for is not in output.
450
451 Returns:
452 True, if output contains parameter |look_for| and |is_in| is True, or
453 False otherwise.
454 """
455 proc = subprocess.Popen(args, stdout=subprocess.PIPE,
456 stderr=subprocess.PIPE)
457 (stdout, stderr) = proc.communicate()
458 lines = (stdout + stderr).splitlines()
459 for line in lines:
460 if look_for in line:
461 return is_in
462 return not is_in
463
464 def _OpenExamplesAndStartTest(self, examples): 209 def _OpenExamplesAndStartTest(self, examples):
465 """Open each example and verify that it's working. 210 """Open each example and verify that it's working.
466 211
467 Args: 212 Args:
468 examples: A dict of name to url of examples. 213 examples: A dict of name to url of examples.
469 """ 214 """
470 self._EnableNaClPlugin() 215 self._EnableNaClPlugin()
471
472 # Open all examples. 216 # Open all examples.
473 for name, url in examples.items(): 217 for name, url in examples.items():
474 self.AppendTab(pyauto.GURL(url)) 218 self.AppendTab(pyauto.GURL(url))
475 self._CheckForCrashes() 219 self._CheckForCrashes()
476 220
477 # Verify all examples are working. 221 # Verify all examples are working.
478 for name, url in examples.items(): 222 for name, url in examples.items():
479 self._VerifyAnExample(name, url) 223 self._VerifyAnExample(name, url)
480 self._CheckForCrashes() 224 self._CheckForCrashes()
481 225
482 # Reload all examples.
483 for _ in range(2):
484 for tab_index in range(self.GetTabCount()):
485 self.GetBrowserWindow(0).GetTab(tab_index).Reload()
486 self._CheckForCrashes()
487
488 # Verify all examples are working.
489 for name, url in examples.items():
490 self._VerifyAnExample(name, url)
491 self._CheckForCrashes()
492
493 # Close each tab, check for crashes and verify all open 226 # Close each tab, check for crashes and verify all open
494 # examples operate correctly. 227 # examples operate correctly.
495 tab_count = self.GetTabCount() 228 tab_count = self.GetTabCount()
496 for index in xrange(tab_count - 1, 0, -1): 229 for index in xrange(tab_count - 1, 0, -1):
497 self.GetBrowserWindow(0).GetTab(index).Close(True) 230 self.GetBrowserWindow(0).GetTab(index).Close(True)
498 self._CheckForCrashes() 231 self._CheckForCrashes()
499 232
500 tabs = self.GetBrowserInfo()['windows'][0]['tabs'] 233 tabs = self.GetBrowserInfo()['windows'][0]['tabs']
501 for tab in tabs: 234 for tab in tabs:
502 if tab['index'] > 0: 235 if tab['index'] > 0:
503 for name, url in examples.items(): 236 for name, url in examples.items():
504 if url == tab['url']: 237 if url == tab['url']:
505 self._VerifyAnExample(name, url) 238 self._VerifyAnExample(name, url)
506 break 239 break
507 240
508 def _VerifyAnExample(self, name, url): 241 def _VerifyAnExample(self, name, url):
509 """Verify NaCl example is working. 242 """Verify NaCl example is working.
510 243
511 Args: 244 Args:
512 name: A string name of the example. 245 name: A string name of the example.
513 url: A string url of the example. 246 url: A string url of the example.
514 """ 247 """
515 available_example_tests = { 248 available_example_tests = {
516 'hello_world_c': self._VerifyHelloWorldExample,
517 'hello_world': self._VerifyHelloWorldExample,
518 'pi_generator': self._VerifyPiGeneratorExample, 249 'pi_generator': self._VerifyPiGeneratorExample,
519 'sine_synth': self._VerifySineSynthExample, 250 'sine_synth': self._VerifySineSynthExample,
520 'geturl': self._VerifyGetURLExample, 251 'geturl': self._VerifyGetURLExample,
521 'life': self._VerifyConwaysLifeExample 252 'input_events': self._VerifyInputEventsExample,
253 'dynamic_library_open': self._VerifyDynamicLibraryOpen,
254 'load_progress': self._VerifyLoadProgressExample,
255 'multithreaded_input_events': self._VerifyMultithreadedInputEventsExample,
256 'web_socket':self._VerifyWebSocketExample,
chrisphan 2012/04/23 02:03:37 Add two more spaces, line 249-256.
Pooja Nihalani 2012/04/23 21:23:54 Done.
522 } 257 }
523 258
524 if not name in available_example_tests: 259 if not name in available_example_tests:
525 self.fail(msg='No test available for %s.' % name) 260 self.fail(msg = 'No test available for %s.' % name)
526 261
527 info = self.GetBrowserInfo() 262 info = self.GetBrowserInfo()
528 tabs = info['windows'][0]['tabs'] 263 tabs = info['windows'][0]['tabs']
529 tab_index = None 264 tab_index = None
530 for tab in tabs: 265 for tab in tabs:
531 if url == tab['url']: 266 if url == tab['url']:
532 self.ActivateTab(tab['index']) 267 self.ActivateTab(tab['index'])
533 tab_index = tab['index'] 268 tab_index = tab['index']
534 break 269 break
535 270
536 if tab_index: 271 if tab_index:
537 available_example_tests[name](tab_index, name, url) 272 available_example_tests[name](tab_index, name, url)
273
274 def _VerifyInputEventsExample(self, tab_index, name, url):
275 """Verify Input Events Example.
538 276
539 def _VerifyHelloWorldExample(self, tab_index, name, url): 277 Args:
540 """Verify Hello World Example. 278 tab_index: Tab index integer that the example is on.
279 name: A string name of the example.
280 url: A string url of the example.
281 """
282 js_code = """
283 var output = document.getElementById("eventString").innerHTML;
284 var result;
285 if (output.indexOf("DidChangeView") != -1)
286 result = "pass";
287 else
288 result = "fail";
289 window.domAutomationController.send(result);
290 """
291 success = self.WaitUntil(
292 lambda: self.ExecuteJavascript(js_code, tab_index),
293 timeout = 60, expect_retval = 'pass')
294 self.assertTrue(success, msg = 'Example %s failed. URL: %s' % (name, url))
295
296 # Simulate mouse click on event module.
297 js_code = """
298 var rightClick = document.createEvent('MouseEvents');
299 rightClick.initMouseEvent(
300 'mousedown', true, true, document,
301 1, 32, 121, 10, 100,
302 false, false, false, false,
303 2, document.getElementById('event_module')
304 );
305 document.getElementById("event_module").dispatchEvent(rightClick);
306 window.domAutomationController.send("done");
307 """
308 self.ExecuteJavascript(js_code, tab_index)
309
310 # Check if 'eventString' has handled above mouse click.
311 success = self.WaitUntil(
312 lambda: re.search('DidHandleInputEvent', self.GetDOMValue(
313 'document.getElementById("eventString").innerHTML',
314 tab_index)).group(), timeout = 30,
315 expect_retval = 'DidHandleInputEvent')
316 self.assertTrue(success, msg = 'Example %s failed. URL: %s' % (name, url))
317
318 def _VerifyMultithreadedInputEventsExample(self, tab_index, name, url):
319 """Verify Input Events Example.
541 320
542 Args: 321 Args:
543 tab_index: Tab index integer that the example is on. 322 tab_index: Tab index integer that the example is on.
544 name: A string name of the example. 323 name: A string name of the example.
545 url: A string url of the example. 324 url: A string url of the example.
546 """ 325 """
547 success = self.WaitUntil( 326 success = self.WaitUntil(
548 lambda: self.GetDOMValue( 327 lambda: bool(self.GetDOMValue(
549 'document.getElementById("statusField").innerHTML', 328 'document.getElementById("eventString").innerHTML',
550 tab_index), 329 tab_index).find('DidChangeView')+1), timeout = 30,
551 timeout=60, expect_retval='SUCCESS') 330 expect_retval = True)
552 self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url)) 331
332 self.assertTrue(success, msg = 'Example %s failed. URL: %s' % (name, url))
553 333
334 # Simulate mouse click on event module.
554 js_code = """ 335 js_code = """
555 window.alert = function(e) { 336 var rightClick = document.createEvent('MouseEvents');
556 window.domAutomationController.send(String(e)); 337 rightClick.initMouseEvent(
557 } 338 'mousedown', true, true, document,
339 1, 432, 121, 10, 100,
340 false, false, false, false,
341 2, document.getElementById('event_module')
342 );
343 document.getElementById("event_module").dispatchEvent(rightClick);
344 window.domAutomationController.send("done");
345 """
346 self.ExecuteJavascript(js_code, tab_index)
347
348 # Check if above mouse click is handled.
349 js_code = """
350 var output = document.getElementById("eventString").innerHTML;
351 var result;
352 if (output.indexOf("Mouse event") != -1)
353 result = "pass";
354 else
355 result = "fail";
356 window.domAutomationController.send(result);
357 """
358 success = self.WaitUntil(
359 lambda: self.ExecuteJavascript(js_code, tab_index),
360 timeout = 30, expect_retval = 'pass')
361 self.assertTrue(success, msg = 'Example %s failed. URL: %s' % (name, url))
362
363 # Kill worker thread and queue
364 js_code = """
365 document.getElementsByTagName('button')[0].click();
558 window.domAutomationController.send("done"); 366 window.domAutomationController.send("done");
559 """ 367 """
560 self.ExecuteJavascript(js_code, tab_index) 368 self.ExecuteJavascript(js_code, tab_index)
561 369
562 result = self.ExecuteJavascript('document.helloForm.elements[1].click();', 370 # Check if main thread has cancelled queue.
563 tab_index) 371 js_code = """
564 self.assertEqual(result, '42', 372 var output = document.getElementById("eventString").innerHTML;
565 msg='Example %s failed. URL: %s' % (name, url)) 373 var result;
374 if (output.indexOf("Received cancel") != -1)
375 result = "pass";
376 else
377 result = "fail";
378 window.domAutomationController.send(result);
379 """
380 success = self.WaitUntil(
381 lambda: self.ExecuteJavascript(js_code, tab_index),
382 timeout = 30, expect_retval = 'pass')
383 self.assertTrue(success, msg = 'Example %s failed. URL: %s' % (name, url))
566 384
567 result = self.ExecuteJavascript('document.helloForm.elements[2].click();', 385 # Simulate mouse click on event module.
568 tab_index) 386 js_code = """
569 self.assertEqual(result, 'dlrow olleH', 387 var rightClick = document.createEvent('MouseEvents');
570 msg='Example %s failed. URL: %s' % (name, url)) 388 rightClick.initMouseEvent(
389 'mousedown', true, true, document,
390 1, 432, 121, 10, 100,
391 false, false, false, false,
392 2 ,document.getElementById('event_module')
393 );
394 document.getElementById("event_module").dispatchEvent(rightClick);
395 window.domAutomationController.send("done");
396 """
397 self.ExecuteJavascript(js_code, tab_index)
571 398
572 def _VerifyPiGeneratorExample(self, tab_index, name, url): 399 # Check if above mouse click is not handled after killing worker thread.
573 """Verify Pi Generator Example. 400 success = self.WaitUntil(
401 lambda: self.GetDOMValue(
402 'document.getElementById("eventString").innerHTML',
403 tab_index).find('Mouse event', self.GetDOMValue(
404 'document.getElementById("eventString").innerHTML', tab_index).find(
405 'Received cancel')), timeout = 30, expect_retval = -1)
406 self.assertTrue(success, msg = 'Example %s failed. URL: %s' % (name, url))
407
408 def _VerifyWebSocketExample(self, tab_index, name, url):
409 """Verify Web Socket Open Example.
574 410
575 Args: 411 Args:
576 tab_index: Tab index integer that the example is on. 412 tab_index: Tab index integer that the example is on.
577 name: A string name of the example. 413 name: A string name of the example.
578 url: A string url of the example. 414 url: A string url of the example.
579 """ 415 """
580 success = self.WaitUntil( 416 # Check if example is loaded.
581 lambda: self.GetDOMValue('document.form.pi.value', 0, tab_index)[0:3],
582 timeout=120, expect_retval='3.1')
583 self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
584
585 # Get top corner of Pi image.
586 js_code = """
587 var obj = document.getElementById('piGenerator');
588 var curleft = curtop = 0;
589 do {
590 curleft += obj.offsetLeft;
591 curtop += obj.offsetTop;
592 } while (obj = obj.offsetParent);
593 window.domAutomationController.send(curleft + ", " + curtop);
594 """
595 result = self.ExecuteJavascript(js_code, tab_index)
596 result_split = result.split(', ')
597 x = int(result_split[0])
598 y = int(result_split[1])
599 window = self.GetBrowserInfo()['windows'][0]
600 window_to_content_x = 2
601 window_to_content_y = 80
602 pi_image_x = x + window['x'] + window_to_content_x
603 pi_image_y = y + window['y'] + window_to_content_y
604
605 if self._IsGetPixelSupported():
606 is_animating = self._IsColorChanging(pi_image_x, pi_image_y, 50, 50)
607 self.assertTrue(is_animating,
608 msg='Example %s failed. URL: %s' % (name, url))
609
610 def _VerifySineSynthExample(self, tab_index, name, url):
611 """Verify Sine Wave Synthesizer Example.
612
613 Args:
614 tab_index: Tab index integer that the example is on.
615 name: A string name of the example.
616 url: A string url of the example.
617 """
618 success = self.WaitUntil( 417 success = self.WaitUntil(
619 lambda: self.GetDOMValue( 418 lambda: self.GetDOMValue(
620 'document.getElementById("frequency_field").value', 419 'document.getElementById("statusField").innerHTML',tab_index),
621 tab_index), 420 timeout = 60, expect_retval = 'SUCCESS')
622 timeout=30, expect_retval='440') 421 self.assertTrue(success, msg = 'Example %s failed. URL: %s' % (name, url))
623 self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
624 422
625 self.ExecuteJavascript( 423 # Simulate clicking on Connect button to establish a connection.
626 'document.body.getElementsByTagName("button")[0].click();' 424 js_code = """
627 'window.domAutomationController.send("done")', 425 document.getElementsByTagName('input')[1].click();
628 tab_index) 426 window.domAutomationController.send("done");
427 """
428 self.ExecuteJavascript(js_code, tab_index)
629 429
630 # TODO(chrisphan): Verify sound. 430 # Check if connected
631
632 def _VerifyGetURLExample(self, tab_index, name, url):
633 """Verify GetURL Example.
634
635 Args:
636 tab_index: Tab index integer that the example is on.
637 name: A string name of the example.
638 url: A string url of the example.
639 """
640 success = self.WaitUntil(
641 lambda: self.GetDOMValue(
642 'document.getElementById("status_field").innerHTML',
643 tab_index),
644 timeout=60, expect_retval='SUCCESS')
645 self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
646
647 self.ExecuteJavascript(
648 'document.geturl_form.elements[0].click();'
649 'window.domAutomationController.send("done")',
650 tab_index)
651
652 js_code = """ 431 js_code = """
653 var output = document.getElementById("general_output").innerHTML; 432 var output = document.getElementById("log").value;
654 var result; 433 var result;
655 if (output.indexOf("test passed") != -1) 434 if (output.indexOf("connected") != -1)
656 result = "pass"; 435 result = "pass";
657 else 436 else
658 result = "fail"; 437 result = "fail";
659 window.domAutomationController.send(result); 438 window.domAutomationController.send(result);
660 """ 439 """
661 success = self.WaitUntil( 440 success = self.WaitUntil(
662 lambda: self.ExecuteJavascript(js_code, tab_index), 441 lambda: self.ExecuteJavascript(js_code, tab_index),
663 timeout=30, expect_retval='pass') 442 timeout = 30, expect_retval = 'pass')
664 self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url)) 443 self.assertTrue(success, msg = 'Example %s failed. URL: %s' % (name, url))
665 444
666 def _VerifyConwaysLifeExample(self, tab_index, name, url): 445 # Simulate clicking on Send button to send text message in log.
667 """Verify Conway's Life Example. 446 js_code = """
447 document.getElementsByTagName('input')[3].click();
448 window.domAutomationController.send("done");
449 """
450 self.ExecuteJavascript(js_code, tab_index)
451 success = self.WaitUntil(
452 lambda: bool(re.search(r"send:",self.GetDOMValue(
453 'document.getElementById("log").value',tab_index))),
454 timeout = 30, expect_retval = True)
455 self.assertTrue(success, msg = 'Example %s failed. URL: %s' % (name, url))
456
457 # Simulate clicking on Close button to establish a connection.
458 js_code = """
459 document.getElementsByTagName('input')[4].click();
460 window.domAutomationController.send("done");
461 """
462 self.ExecuteJavascript(js_code, tab_index)
chrisphan 2012/04/23 02:03:37 Not asserting anything, you can remove line 457-46
Pooja Nihalani 2012/04/23 21:23:54 Done.
463
464 def _VerifyDynamicLibraryOpen(self, tab_index, name, url):
465 """Verify Dynamic Library Open Example.
668 466
669 Args: 467 Args:
670 tab_index: Tab index integer that the example is on. 468 tab_index: Tab index integer that the example is on.
671 name: A string name of the example. 469 name: A string name of the example.
672 url: A string url of the example. 470 url: A string url of the example.
673 """ 471 """
674 window = self.GetBrowserInfo()['windows'][0] 472 # Check if example is loaded.
675 window_to_content_x = 2 473 js_code = """
676 window_to_content_y = 80 474 var output = document.getElementById("consolec").innerHTML;
677 x = window['x'] + window_to_content_x 475 var result;
678 y = window['y'] + window_to_content_y 476 if (output.indexOf("Eightball loaded") != -1)
679 offset_pixel = 100 477 result = "pass";
680 if self._IsGetPixelSupported(): 478 else
681 success = self.WaitUntil( 479 result = "fail";
682 lambda: self._GetPixel(x + offset_pixel, y + offset_pixel), 480 window.domAutomationController.send(result);
683 timeout=30, expect_retval=16777215) 481 """
684 self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url)) 482 success = self.WaitUntil(
483 lambda: self.ExecuteJavascript(js_code, tab_index),
484 timeout = 60, expect_retval = 'pass')
485 self.assertTrue(success, msg = 'Example %s failed. URL: %s' % (name, url))
685 486
686 def _GetXMLNodeData(self, nodelist): 487 # Simulate clicking on ASK button and check answer log for desired answer.
687 rc = [] 488 js_code = """
688 for node in nodelist: 489 document.getElementsByTagName('input')[1].click();
689 if node.nodeType == node.TEXT_NODE: 490 window.domAutomationController.send("done");
690 rc.append(node.data) 491 """
691 return ''.join(rc) 492 self.ExecuteJavascript(js_code, tab_index)
493 success = self.WaitUntil(
494 lambda: bool(
495 re.search(r"NO|YES|42|MAYBE NOT|DEFINITELY|"
chrisphan 2012/04/23 02:03:37 Single quote
Pooja Nihalani 2012/04/23 21:23:54 Done.
496 "ASK ME TOMORROW|MAYBE|PARTLY CLOUDY",
497 self.GetDOMValue('document.getElementById("answerlog").innerHTML',
498 tab_index))), timeout = 30, expect_retval = True)
499 self.assertTrue(success, msg = 'Example %s failed. URL: %s' % (name, url))
692 500
693 def _IsColorChanging(self, x, y, width, height): 501 def _VerifyLoadProgressExample(self, tab_index, name, url):
694 """Check screen for anything that is moving. 502 """Verify Dynamic Library Open Example.
695 503
696 Args: 504 Args:
697 x: X coordinate on the screen. 505 tab_index: Tab index integer that the example is on.
698 y: Y coordinate on the screen. 506 name: A string name of the example.
699 width: Width of the area to scan. 507 url: A string url of the example.
700 height: Height of the area to scan. 508 """
509 # Check if example loads and displays loading progress.
510 success = self.WaitUntil(
511 lambda: self.GetDOMValue(
512 'document.getElementById("status_field").innerHTML', tab_index),
513 timeout = 60, expect_retval = 'SUCCESS')
514 self.assertTrue(success, msg = 'Example %s failed. URL: %s' % (name, url))
515 success = self.WaitUntil(
516 lambda: bool(
517 re.search(r"(loadstart).+(progress:).+(load).+(loadend).+(lastError:)",
chrisphan 2012/04/23 02:03:37 single quote
Pooja Nihalani 2012/04/23 21:23:54 Done.
518 self.GetDOMValue('document.getElementById("event_log_field").innerHTML',
519 tab_index))),timeout = 10, expect_retval = True)
520 self.assertTrue(success, msg = 'Example %s failed. URL: %s' % (name, url))
701 521
702 Returns: 522 def _VerifyPiGeneratorExample(self, tab_index, name, url):
703 True, if pixel color in area is changing, or 523 """Verify Pi Generator Example.
704 False otherwise.
705 """
706 color_a = self._GetAreaPixelColor(x, y, width, height)
707 def _HasColorChanged():
708 color_b = self._GetAreaPixelColor(x, y, width, height)
709 return color_a != color_b
710
711 return self.WaitUntil(_HasColorChanged, timeout=6,
712 retry_sleep=2, expect_retval=True)
713
714 def _IsGetPixelSupported(self):
715 """Check if get pixel is supported.
716
717 Returns:
718 True, if get pixel is supported, or
719 False otherwise.
720 """
721 return pyauto.PyUITest.IsWin()
722
723 def _GetAreaPixelColor(self, x, y, width, height):
724 """Get an area of pixel color and return a list of color code values.
725 524
726 Args: 525 Args:
727 x: X coordinate on the screen. 526 tab_index: Tab index integer that the example is on.
728 y: Y coordinate on the screen. 527 name: A string name of the example.
729 width: Width of the area to scan. 528 url: A string url of the example.
730 height: Height of the area to scan. 529 """
530 success = self.WaitUntil(
531 lambda: self.GetDOMValue('document.form.pi.value', tab_index)[0:3],
532 timeout = 30, expect_retval = '3.1')
533 self.assertTrue(success, msg = 'Example %s failed. URL: %s' % (name, url))
731 534
732 Returns: 535 def _VerifySineSynthExample(self, tab_index, name, url):
733 A list containing color codes. 536 """Verify Sine Wave Synthesizer Example.
734 """
735 if pyauto.PyUITest.IsMac():
736 pass # TODO(chrisphan): Do Mac.
737 elif pyauto.PyUITest.IsWin():
738 return self._GetAreaPixelColorWin(x, y, width, height)
739 elif pyauto.PyUITest.IsLinux():
740 pass # TODO(chrisphan): Do Linux.
741 return None
742
743 def _GetAreaPixelColorWin(self, x, y, width, height):
744 """Get an area of pixel color for Windows and return a list.
745 537
746 Args: 538 Args:
747 x: X coordinate on the screen. 539 tab_index: Tab index integer that the example is on.
748 y: Y coordinate on the screen. 540 name: A string name of the example.
749 width: Width of the area to scan. 541 url: A string url of the example.
750 height: Height of the area to scan. 542 """
543 success = self.WaitUntil(
544 lambda: self.GetDOMValue(
545 'document.getElementById("frequency_field").value',
546 tab_index),
547 timeout = 40, expect_retval = '440')
548 self.assertTrue(success, msg = 'Example %s failed. URL: %s' % (name, url))
549 self.ExecuteJavascript(
550 'document.body.getElementsByTagName("button")[0].click();'
551 'window.domAutomationController.send("done")',
552 tab_index)
751 553
752 Returns: 554 def _VerifyGetURLExample(self, tab_index, name, url):
753 A list containing color codes. 555 """Verify GetURL Example.
754 """
755 colors = []
756 hdc = ctypes.windll.user32.GetDC(0)
757 for x_pos in xrange(x, x + width, 1):
758 for y_pos in xrange(y, y + height, 1):
759 color = ctypes.windll.gdi32.GetPixel(hdc, x_pos, y_pos)
760 colors.append(color)
761 return colors
762
763 def _GetPixel(self, x, y):
764 """Get pixel color at coordinate x and y.
765 556
766 Args: 557 Args:
767 x: X coordinate on the screen. 558 tab_index: Tab index integer that the example is on.
768 y: Y coordinate on the screen. 559 name: A string name of the example.
560 url: A string url of the example.
561 """
562 success = self.WaitUntil(
563 lambda: self.GetDOMValue(
564 'document.getElementById("status_field").innerHTML',
565 tab_index),
566 timeout = 60, expect_retval = 'SUCCESS')
567 self.assertTrue(success, msg = 'Example %s failed. URL: %s' % (name, url))
568 self.ExecuteJavascript(
569 'document.geturl_form.elements[0].click();'
570 'window.domAutomationController.send("done")',
571 tab_index)
572 js_code = """
573 var output = document.getElementById("general_output").innerHTML;
574 var result;
575 if (output.indexOf("test passed") != -1)
576 result = "pass";
577 else
578 result = "fail";
579 window.domAutomationController.send(result);
580 """
581 success = self.WaitUntil(
582 lambda: self.ExecuteJavascript(js_code, tab_index),
583 timeout = 60, expect_retval = 'pass')
584 self.assertTrue(success, msg = 'Example %s failed. URL: %s' % (name, url))
769 585
770 Returns: 586 def _CheckForCrashes(self):
771 An integer color code. 587 """Check for any browser/tab crashes and hangs."""
772 """
773 if pyauto.PyUITest.IsMac():
774 pass # TODO(chrisphan): Do Mac.
775 elif pyauto.PyUITest.IsWin():
776 return self._GetPixelWin(x, y)
777 elif pyauto.PyUITest.IsLinux():
778 pass # TODO(chrisphan): Do Linux.
779 return None
780
781 def _GetPixelWin(self, x, y):
782 """Get pixel color at coordinate x and y for Windows
783
784 Args:
785 x: X coordinate on the screen.
786 y: Y coordinate on the screen.
787
788 Returns:
789 An integer color code.
790 """
791 hdc = ctypes.windll.user32.GetDC(0)
792 color = ctypes.windll.gdi32.GetPixel(hdc, x, y)
793 return color
794
795 def _CheckForCrashes(self, last_action=None, last_action_param=None):
796 """Check for any browser/tab crashes and hangs.
797
798 Args:
799 last_action: Specify action taken before checking for crashes.
800 last_action_param: Parameter for last action.
801 """
802 self.assertTrue(self.GetBrowserWindowCount(), 588 self.assertTrue(self.GetBrowserWindowCount(),
803 msg='Browser crashed, no window is open.') 589 msg = 'Browser crashed, no window is open.')
804 590
805 info = self.GetBrowserInfo() 591 info = self.GetBrowserInfo()
806 breakpad_folder = info['properties']['DIR_CRASH_DUMPS'] 592 breakpad_folder = info['properties']['DIR_CRASH_DUMPS']
807 old_dmp_files = glob.glob(os.path.join(breakpad_folder, '*.dmp')) 593 old_dmp_files = glob.glob(os.path.join(breakpad_folder, '*.dmp'))
808 594
809 # Verify there're no crash dump files. 595 # Verify there're no crash dump files.
810 for dmp_file in glob.glob(os.path.join(breakpad_folder, '*.dmp')): 596 for dmp_file in glob.glob(os.path.join(breakpad_folder, '*.dmp')):
811 self.assertTrue(dmp_file in old_dmp_files, 597 self.assertTrue(dmp_file in old_dmp_files,
812 msg='Crash dump %s found' % dmp_file) 598 msg = 'Crash dump %s found' % dmp_file)
813 599
814 # Check for any crashed tabs. 600 # Check for any crashed tabs.
815 tabs = info['windows'][0]['tabs'] 601 tabs = info['windows'][0]['tabs']
816 for tab in tabs: 602 for tab in tabs:
817 if tab['url'] != 'about:blank': 603 if tab['url'] != 'about:blank':
818 if not self.GetDOMValue('document.body.innerHTML', tab['index']): 604 if not self.GetDOMValue('document.body.innerHTML', tab['index']):
819 self.fail(msg='Tab crashed on %s' % tab['url']) 605 self.fail(msg = 'Tab crashed on %s' % tab['url'])
820
821 # TODO(chrisphan): Check for tab hangs and browser hangs.
822 # TODO(chrisphan): Handle specific action: close browser, close tab.
823 if last_action == 'close tab':
824 pass
825 elif last_action == 'close browser':
826 pass
827 else:
828 pass
829 606
830 def _GetPlatformArchitecture(self): 607 def _GetPlatformArchitecture(self):
831 """Get platform architecture. 608 """Get platform architecture.
832 609
833 Args:
834 last_action: Last action taken before checking for crashes.
835 last_action_param: Parameter for last action.
836
837 Returns: 610 Returns:
838 A string representing the platform architecture. 611 A string representing the platform architecture.
839 """ 612 """
840 if pyauto.PyUITest.IsWin(): 613 if pyauto.PyUITest.IsWin():
841 if os.environ['PROGRAMFILES'] == 'C:\\Program Files (x86)': 614 if os.environ['PROGRAMFILES'] == 'C:\\Program Files (x86)':
842 return '64bit' 615 return '64bit'
843 else: 616 else:
844 return '32bit' 617 return '32bit'
845 elif pyauto.PyUITest.IsMac() or pyauto.PyUITest.IsLinux(): 618 elif pyauto.PyUITest.IsMac() or pyauto.PyUITest.IsLinux():
846 if platform.machine() == 'x86_64': 619 if platform.machine() == 'x86_64':
847 return '64bit' 620 return '64bit'
848 else: 621 else:
849 return '32bit' 622 return '32bit'
850 return '32bit' 623 return '32bit'
851 624
852 def _HasFile(self, pattern, root=os.curdir): 625 def _HasPathInTree(self, pattern, is_file, root = os.curdir):
853 """Check if a file matching the specified pattern exists in a directory.
854
855 Args:
856 pattern: Pattern of file name.
857 root: Directory to start looking.
858
859 Returns:
860 True, if root contains the file name pattern, or
861 False otherwise.
862 """
863 return len(glob.glob(os.path.join(root, pattern)))
864
865 def _HasPathInTree(self, pattern, is_file, root=os.curdir):
866 """Recursively checks if a file/directory matching a pattern exists. 626 """Recursively checks if a file/directory matching a pattern exists.
867 627
868 Args: 628 Args:
869 pattern: Pattern of file or directory name. 629 pattern: Pattern of file or directory name.
870 is_file: True if looking for file, or False if looking for directory. 630 is_file: True if looking for file, or False if looking for directory.
871 root: Directory to start looking. 631 root: Directory to start looking.
872 632
873 Returns: 633 Returns:
874 True, if root contains the directory name pattern, or 634 True, if root contains the directory name pattern, or
875 False otherwise. 635 False otherwise.
876 """ 636 """
877 for path, dirs, files in os.walk(os.path.abspath(root)): 637 for path, dirs, files in os.walk(os.path.abspath(root)):
878 if is_file: 638 if is_file:
879 if len(fnmatch.filter(files, pattern)): 639 if len(fnmatch.filter(files, pattern)):
880 return True 640 return True
881 else: 641 else:
882 if len(fnmatch.filter(dirs, pattern)): 642 if len(fnmatch.filter(dirs, pattern)):
883 return True 643 return True
884 return False 644 return False
885 645
886 def _GetDirectoryPath(self, pattern, root=os.curdir):
887 """Get the path of a directory in another directory.
888
889 Args:
890 pattern: Pattern of directory name.
891 root: Directory to start looking.
892
893 Returns:
894 A string of the path.
895 """
896 for path, dirs, files in os.walk(os.path.abspath(root)):
897 result = fnmatch.filter(dirs, pattern)
898 if result:
899 return os.path.join(path, result[0])
900 return None
901
902 def _HasAllSystemRequirements(self): 646 def _HasAllSystemRequirements(self):
903 """Verify NaCl SDK installation system requirements. 647 """Verify NaCl SDK installation system requirements.
904 648
905 Returns: 649 Returns:
906 True, if system passed requirements, or 650 True, if system passed requirements, or
907 False otherwise. 651 False otherwise.
908 """ 652 """
909 # Check python version. 653 # Check python version.
910 if sys.version_info[0:2] < (2, 6): 654 if sys.version_info[0:2] < (2, 6):
911 return False 655 return False
(...skipping 16 matching lines...) Expand all
928 # NaCl supports Chrome 10 and higher builds. 672 # NaCl supports Chrome 10 and higher builds.
929 min_required_chrome_build = self._settings['min_required_chrome_build'] 673 min_required_chrome_build = self._settings['min_required_chrome_build']
930 browser_info = self.GetBrowserInfo() 674 browser_info = self.GetBrowserInfo()
931 chrome_version = browser_info['properties']['ChromeVersion'] 675 chrome_version = browser_info['properties']['ChromeVersion']
932 chrome_build = int(chrome_version.split('.')[0]) 676 chrome_build = int(chrome_version.split('.')[0])
933 return chrome_build >= min_required_chrome_build 677 return chrome_build >= min_required_chrome_build
934 678
935 def _DownloadNaClSDK(self): 679 def _DownloadNaClSDK(self):
936 """Download NaCl SDK.""" 680 """Download NaCl SDK."""
937 self._temp_dir = tempfile.mkdtemp() 681 self._temp_dir = tempfile.mkdtemp()
938 if pyauto.PyUITest.IsWin(): 682 dl_file = urllib2.urlopen(self._settings['post_sdk_url'])
939 dl_file = urllib2.urlopen(self._settings['release_win_sdk_url']) 683 file_path = os.path.join(self._temp_dir, 'nacl_sdk.zip')
940 file_path = os.path.join(self._temp_dir, 'naclsdk_win.exe')
941 elif pyauto.PyUITest.IsMac():
942 dl_file = urllib2.urlopen(self._settings['release_mac_sdk_url'])
943 file_path = os.path.join(self._temp_dir, 'naclsdk_mac.tgz')
944 elif pyauto.PyUITest.IsLinux():
945 dl_file = urllib2.urlopen(self._settings['release_lin_sdk_url'])
946 file_path = os.path.join(self._temp_dir, 'naclsdk_linux.tgz')
947 else:
948 self.fail(msg='NaCl SDK does not support this OS.')
949 684
950 try: 685 try:
951 f = open(file_path, 'wb') 686 f = open(file_path, 'wb')
952 f.write(dl_file.read()) 687 f.write(dl_file.read())
953 except IOError: 688 except IOError:
954 self.fail(msg='Cannot open %s.' % file_path) 689 self.fail(msg = 'Cannot open %s.' % file_path)
955 finally: 690 finally:
956 f.close() 691 f.close()
957 692
958 def _ExtractNaClSDK(self): 693 def _ExtractNaClSDK(self):
959 """Extract NaCl SDK.""" 694 """Extract NaCl SDK."""
960 if pyauto.PyUITest.IsWin(): 695 source_file = os.path.join(self._temp_dir, 'nacl_sdk.zip')
961 source_file = os.path.join(self._temp_dir, 'naclsdk_win.exe') 696 if zipfile.is_zipfile(source_file):
962 proc = subprocess.Popen([source_file, '/S', '/D=' + 697 zip = zipfile.ZipFile(source_file, 'r')
963 self._extracted_sdk_path], 698 xpath = self._extracted_sdk_path
964 stdout=subprocess.PIPE) 699 zip.extractall(xpath)
chrisphan 2012/04/23 02:03:37 use inline: zip.extractall(self._extracted_sdk_pa
Pooja Nihalani 2012/04/23 21:23:54 Done.
965 proc.communicate()
966 if not os.listdir(self._extracted_sdk_path):
967 self.fail(msg='Failed to extract NaCl SDK.')
968 elif pyauto.PyUITest.IsMac():
969 source_file = os.path.join(self._temp_dir, 'naclsdk_mac.tgz')
970 tar = tarfile.open(source_file, 'r')
971 tar.extractall(self._extracted_sdk_path)
972 elif pyauto.PyUITest.IsLinux():
973 source_file = os.path.join(self._temp_dir, 'naclsdk_linux.tgz')
974 tar = tarfile.open(source_file, 'r')
975 tar.extractall(self._extracted_sdk_path)
976 else: 700 else:
977 self.fail(msg='NaCl SDK does not support this OS.') 701 self.fail(msg = '%s is not a valid zip file' % source_file)
978 702
979 def _IsURLAlive(self, url): 703 def _IsURLAlive(self, url):
980 """Test if URL is alive.""" 704 """Test if URL is alive."""
981 try: 705 try:
982 urllib2.urlopen(url) 706 urllib2.urlopen(url)
983 except: 707 except:
984 return False 708 return False
985 return True 709 return True
986 710
987 def _CloseHTTPServer(self, proc=None): 711 def _CloseHTTPServer(self, proc = None):
988 """Close HTTP server. 712 """Close HTTP server.
989 713
990 Args: 714 Args:
991 proc: Process that opened the HTTP server. 715 proc: Process that opened the HTTP server.
992 proc is None when there is no pointer to HTTP server process. 716 proc is None when there is no pointer to HTTP server process.
993 """ 717 """
994 if not self._IsURLAlive('http://localhost:5103'): 718 if not self._IsURLAlive('http://localhost:5103'):
995 return 719 return
996 response = urllib2.urlopen('http://localhost:5103') 720 response = urllib2.urlopen('http://localhost:5103')
997 html = response.read() 721 html = response.read()
998 if not 'Native Client' in html: 722 if not 'Native Client' in html:
999 self.fail(msg='Port 5103 is in use.') 723 self.fail(msg = 'Port 5103 is in use.')
1000 724
1001 urllib2.urlopen('http://localhost:5103?quit=1') 725 urllib2.urlopen('http://localhost:5103?quit=1')
1002 success = self.WaitUntil( 726 success = self.WaitUntil(
1003 lambda: self._IsURLAlive('http://localhost:5103'), 727 lambda: self._IsURLAlive('http://localhost:5103'),
1004 timeout=30, retry_sleep=1, expect_retval=False) 728 timeout = 30, retry_sleep = 1, expect_retval = False)
1005 if not success: 729 if not success:
1006 if not proc: 730 if not proc:
1007 self.fail(msg='Failed to close HTTP server.') 731 self.fail(msg = 'Failed to close HTTP server.')
1008 else: 732 else:
1009 if proc.poll() == None: 733 if proc.poll() == None:
1010 try: 734 try:
1011 proc.kill() 735 proc.kill()
1012 except: 736 except:
1013 self.fail(msg='Failed to close HTTP server') 737 self.fail(msg = 'Failed to close HTTP server.')
1014 738
1015 def _SearchNaClSDKTarFile(self, search_list, source_file): 739 def _SearchNaClSDKFile(self, search_list):
1016 """Search NaCl SDK tar file for example files and directories.
1017
1018 Args:
1019 search_list: A list of strings, representing file and
1020 directory names for which to search.
1021 source_file: The string name of an NaCl SDK tar file.
1022 """
1023 tar = tarfile.open(source_file, 'r')
1024
1025 # Look for files and directories in examples.
1026 files = copy.deepcopy(search_list)
1027 for tar_info in tar:
1028 file_name = tar_info.name
1029 if tar_info.isdir() and not file_name.endswith('/'):
1030 file_name = file_name + '/'
1031
1032 for name in files:
1033 if file_name.find('examples/' + name):
1034 files.remove(name)
1035 if not files:
1036 break
1037
1038 tar.close()
1039
1040 self.assertEqual(len(files), 0,
1041 msg='Missing files or directories: %s' %
1042 ', '.join(map(str, files)))
1043
1044 def _SearchNaClSDKFileWindows(self, search_list):
1045 """Search NaCl SDK file for example files and directories in Windows. 740 """Search NaCl SDK file for example files and directories in Windows.
1046 741
1047 Args: 742 Args:
1048 search_list: A list of strings, representing file and 743 search_list: A list of strings, representing file and
1049 directory names for which to search. 744 directory names for which to search.
1050 """ 745 """
1051 missing_items = [] 746 missing_items = []
1052 for name in search_list: 747 for name in search_list:
1053 is_file = name.find('/') < 0 748 is_file = name.find('/') < 0
1054 if not is_file: 749 if not is_file:
1055 name = name.replace('/', '') 750 name = name.replace('/', '')
1056 if not self._HasPathInTree(name, is_file, self._extracted_sdk_path): 751 if not self._HasPathInTree(name, is_file, self._extracted_sdk_path):
1057 missing_items.append(name) 752 missing_items.append(name)
1058 self.assertEqual(len(missing_items), 0, 753 self.assertEqual(len(missing_items), 0,
1059 msg='Missing files or directories: %s' % 754 msg = 'Missing files or directories: %s' %
1060 ', '.join(map(str, missing_items))) 755 ', '.join(map(str, missing_items)))
1061 756
757 def ExtraChromeFlags(self):
chrisphan 2012/04/23 02:03:37 Do they want you to use Chrome flags to enable NaC
Pooja Nihalani 2012/04/23 21:23:54 Yes they want chrome flags to be enabled. On 2012
758 """Ensures Nacl is enabled.
759
760 Returns:
761 A list of extra flags to pass to Chrome when it is launched.
762 """
763 return ['--flag-switches-begin',
764 '--enable-nacl',
765 '--enable-nacl-exception-handling',
766 '--nacl-gdb',
767 '--flag-switches-end'
768 ]
769
1062 def _EnableNaClPlugin(self): 770 def _EnableNaClPlugin(self):
1063 """Enable NaCl plugin.""" 771 """Enable NaCl plugin."""
1064 nacl_plugin = (self.GetPluginsInfo().PluginForName('Chrome NaCl') or 772 nacl_plugin = (self.GetPluginsInfo().PluginForName('Chrome NaCl') or
1065 self.GetPluginsInfo().PluginForName('Native Client')) 773 self.GetPluginsInfo().PluginForName('Native Client'))
1066 if not nacl_plugin: 774 if not nacl_plugin:
1067 self.fail(msg='No NaCl plugin found.') 775 self.fail(msg = 'No NaCl plugin found.')
1068 self.EnablePlugin(nacl_plugin[0]['path']) 776 self.EnablePlugin(nacl_plugin[0]['path'])
1069 777
1070 self.NavigateToURL('about:flags') 778 self.NavigateToURL('about:flags')
1071 779
1072 js_code = """ 780 js_code = """
1073 chrome.send('enableFlagsExperiment', ['enable-nacl', 'true']); 781 chrome.send('enableFlagsExperiment', ['enable-nacl', 'true']);
1074 requestFlagsExperimentsData(); 782 requestFlagsExperimentsData();
1075 window.domAutomationController.send('done'); 783 window.domAutomationController.send('done');
1076 """ 784 """
1077 self.ExecuteJavascript(js_code) 785 self.ExecuteJavascript(js_code)
1078 self.RestartBrowser(False) 786 self.RestartBrowser(False)
1079 787
1080 self.NavigateToURL('about://version') 788 self.NavigateToURL('about://version')
1081 self.assertEqual(self.FindInPage('--enable-nacl')['match_count'], 1, 789 self.assertNotEquals(self.FindInPage('--enable-nacl')['match_count'], 0,
chrisphan 2012/04/23 02:03:37 Are you sure this is tab 0?
Pooja Nihalani 2012/04/23 21:23:54 Self.assertNotEquals.. is tabbed as in to fall in
1082 msg='Missing expected Chrome flag --enable-nacl.') 790 msg = 'Missing expected Chrome flag --enable-nacl.')
1083 791
1084 792
1085 if __name__ == '__main__': 793 if __name__ == '__main__':
1086 pyauto_functional.Main() 794 pyauto_functional.Main()
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698