OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python |
| 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 |
| 4 # found in the LICENSE file. |
| 5 |
| 6 import copy |
| 7 import ctypes |
| 8 from distutils import version |
| 9 import fnmatch |
| 10 import glob |
| 11 import hashlib |
| 12 import logging |
| 13 import os |
| 14 import platform |
| 15 import shutil |
| 16 import subprocess |
| 17 import sys |
| 18 import tarfile |
| 19 import time |
| 20 import urllib2 |
| 21 |
| 22 import pyauto_functional # Must be imported before pyauto. |
| 23 import pyauto |
| 24 |
| 25 class NaClSDKTest(pyauto.PyUITest): |
| 26 """Tests for the NaCl SDK.""" |
| 27 _download_dir = os.path.join(pyauto.PyUITest.DataDir(), 'downloads') |
| 28 _extracted_sdk_path = os.path.join(_download_dir, 'extracted_nacl_sdk') |
| 29 |
| 30 def setUp(self): |
| 31 pyauto.PyUITest.setUp(self) |
| 32 self._RemoveDownloadedTestFile() |
| 33 |
| 34 def testNaClSDK(self): |
| 35 """Verify that NaCl SDK is working properly.""" |
| 36 if not self._HasAllSystemRequirements(): |
| 37 logging.info('System does not meet the requirements.') |
| 38 return |
| 39 |
| 40 self._VerifyDownloadLinks() |
| 41 self._VerifyNaClSDKInstaller() |
| 42 self._VerifyBuildStubProject() |
| 43 self._LaunchServerAndVerifyExamples() |
| 44 self._VerifyRebuildExamples() |
| 45 self._VerifySelldrAndNcval() |
| 46 |
| 47 def testVerifyNaClSDKChecksum(self): |
| 48 """Verify NaCl SDK Checksum.""" |
| 49 if not self._HasAllSystemRequirements(): |
| 50 logging.info('System does not meet the requirements.') |
| 51 return |
| 52 |
| 53 settings = self._GetTestSetting() |
| 54 |
| 55 self._DownloadNaClSDK() |
| 56 |
| 57 if pyauto.PyUITest.IsWin(): |
| 58 expected_shasum = settings['release_win_expected_shasum'] |
| 59 file_path = os.path.join(self._download_dir, 'naclsdk_win.exe') |
| 60 elif pyauto.PyUITest.IsMac(): |
| 61 expected_shasum = settings['release_mac_expected_shasum'] |
| 62 file_path = os.path.join(self._download_dir, 'naclsdk_mac.tgz') |
| 63 elif pyauto.PyUITest.IsLinux(): |
| 64 expected_shasum = settings['release_lin_expected_shasum'] |
| 65 file_path = os.path.join(self._download_dir, 'naclsdk_linux.tgz') |
| 66 else: |
| 67 self.fail(msg='NaCl SDK does not support this OS.') |
| 68 |
| 69 sha = hashlib.sha1() |
| 70 try: |
| 71 f = open(file_path, 'rb') |
| 72 sha.update(f.read()) |
| 73 shasum = sha.hexdigest() |
| 74 self.assertEqual(expected_shasum, shasum, |
| 75 msg='Unexpected checksum. Expected: %s, got: %s' |
| 76 % (expected_shasum, shasum)) |
| 77 except IOError: |
| 78 self.fail(msg='Cannot open %s.' % file_path) |
| 79 finally: |
| 80 f.close() |
| 81 |
| 82 def testVerifyNaClPlugin(self): |
| 83 """Verify NaCl plugin.""" |
| 84 if not self._HasAllSystemRequirements(): |
| 85 logging.info('System does not meet the requirements.') |
| 86 return |
| 87 self._OpenExamplesAndStartTest( |
| 88 self._GetTestSetting()['gallery_examples']) |
| 89 |
| 90 def testVerifyPrereleaseGallery(self): |
| 91 """Verify Pre-release gallery examples.""" |
| 92 if not self._HasAllSystemRequirements(): |
| 93 logging.info('System does not meet the requirements.') |
| 94 return |
| 95 self._OpenExamplesAndStartTest( |
| 96 self._GetTestSetting()['prerelease_gallery']) |
| 97 |
| 98 def _VerifyDownloadLinks(self): |
| 99 """Verify the download links.""" |
| 100 settings = self._GetTestSetting() |
| 101 self.NavigateToURL(settings['post_sdk_download_url']) |
| 102 html = self.GetTabContents() |
| 103 |
| 104 # Make sure the correct URL is under the correct label. |
| 105 if pyauto.PyUITest.IsWin(): |
| 106 win_sdk_url = settings['post_win_sdk_url'] |
| 107 win_url_index = html.find(win_sdk_url) |
| 108 self.assertTrue(win_url_index > -1, |
| 109 msg='Missing SDK download URL: %s' % win_sdk_url) |
| 110 win_keyword_index = html.rfind('Windows', 0, win_url_index) |
| 111 self.assertTrue(win_keyword_index > -1, |
| 112 msg='Misplaced download link: %s' % win_sdk_url) |
| 113 elif pyauto.PyUITest.IsMac(): |
| 114 mac_sdk_url = settings['post_mac_sdk_url'] |
| 115 mac_url_index = html.find(mac_sdk_url) |
| 116 self.assertTrue(mac_url_index > -1, |
| 117 msg='Missing SDK download URL: %s' % mac_sdk_url) |
| 118 mac_keyword_index = html.rfind('Macintosh', 0, mac_url_index) |
| 119 self.assertTrue(mac_keyword_index > -1, |
| 120 msg='Misplaced download link: %s' % mac_sdk_url) |
| 121 elif pyauto.PyUITest.IsLinux(): |
| 122 lin_sdk_url = settings['post_lin_sdk_url'] |
| 123 lin_url_index = html.find(lin_sdk_url) |
| 124 self.assertTrue(lin_url_index > -1, |
| 125 msg='Missing SDK download URL: %s' % lin_sdk_url) |
| 126 lin_keyword_index = html.rfind('Linux', 0, lin_url_index) |
| 127 self.assertTrue(lin_keyword_index > -1, |
| 128 msg='Misplaced download link: %s' % lin_sdk_url) |
| 129 else: |
| 130 self.fail(msg='NaCl SDK does not support this OS.') |
| 131 |
| 132 def _VerifyNaClSDKInstaller(self): |
| 133 """Verify NaCl SDK installer.""" |
| 134 search_list = [ |
| 135 'build.scons', |
| 136 'favicon.ico', |
| 137 'geturl/', |
| 138 'hello_world/', |
| 139 'hello_world_c/', |
| 140 'httpd.py', |
| 141 'index.html', |
| 142 'nacl_sdk_scons/', |
| 143 'pi_generator/', |
| 144 'scons', |
| 145 'sine_synth/' |
| 146 ] |
| 147 |
| 148 mac_lin_additional_search_items = [ |
| 149 'sel_ldr_x86_32', |
| 150 'sel_ldr_x86_64', |
| 151 'ncval_x86_32', |
| 152 'ncval_x86_64' |
| 153 ] |
| 154 |
| 155 win_additional_search_items = [ |
| 156 'httpd.cmd', |
| 157 'sel_ldr_x86_32.exe', |
| 158 'sel_ldr_x86_64.exe', |
| 159 'ncval_x86_32.exe', |
| 160 'ncval_x86_64.exe' |
| 161 ] |
| 162 |
| 163 self._DownloadNaClSDK() |
| 164 |
| 165 if pyauto.PyUITest.IsWin(): |
| 166 source_file = os.path.join(self._download_dir, 'naclsdk_win.exe') |
| 167 self._SearchNaClSDKFileWindows( |
| 168 search_list + win_additional_search_items, source_file) |
| 169 elif pyauto.PyUITest.IsMac(): |
| 170 source_file = os.path.join(self._download_dir, 'naclsdk_mac.tgz') |
| 171 self._SearchNaClSDKTarFile(search_list + mac_lin_additional_search_items, |
| 172 source_file) |
| 173 elif pyauto.PyUITest.IsLinux(): |
| 174 source_file = os.path.join(self._download_dir, 'naclsdk_linux.tgz') |
| 175 self._SearchNaClSDKTarFile(search_list + mac_lin_additional_search_items, |
| 176 source_file) |
| 177 else: |
| 178 self.fail(msg='NaCl SDK does not support this OS.') |
| 179 |
| 180 self._ExtractNaClSDK() |
| 181 |
| 182 def _VerifyBuildStubProject(self): |
| 183 """Build stub project.""" |
| 184 stub_project_files = [ |
| 185 'build.scons', |
| 186 'scons' |
| 187 ] |
| 188 project_template_path = self._GetDirectoryPath('project_templates', |
| 189 self._extracted_sdk_path) |
| 190 examples_path = self._GetDirectoryPath('examples', |
| 191 self._extracted_sdk_path) |
| 192 init_project_path = os.path.join(project_template_path, 'init_project.py') |
| 193 |
| 194 # Build a C project. |
| 195 self._BuildStubProject(init_project_path, 'hello_c', examples_path, |
| 196 stub_project_files) |
| 197 |
| 198 # Build a C++ project. |
| 199 self._BuildStubProject(init_project_path, 'hello_cc', examples_path, |
| 200 stub_project_files) |
| 201 |
| 202 def _BuildStubProject(self, init_project_path, name, examples_path, |
| 203 stub_project_files): |
| 204 """Build stub project.""" |
| 205 proc = subprocess.Popen( |
| 206 ['python', init_project_path, '-n', name, '-c', '-d', |
| 207 examples_path], stdout=subprocess.PIPE) |
| 208 proc.communicate() |
| 209 |
| 210 hello_c_path = os.path.join(examples_path, name) |
| 211 for file in stub_project_files: |
| 212 self.assertTrue(self._HasFile(file, hello_c_path), |
| 213 msg='Cannot build %s stub project.' % name) |
| 214 |
| 215 def _LaunchServerAndVerifyExamples(self): |
| 216 """Start local HTTP server and verify examples.""" |
| 217 # Make sure server is not open. |
| 218 if self._IsURLAlive('http://localhost:5103'): |
| 219 self._CloseHTTPServer() |
| 220 |
| 221 # Start HTTP server. |
| 222 examples_path = self._GetDirectoryPath('examples', |
| 223 self._extracted_sdk_path) |
| 224 if pyauto.PyUITest.IsWin(): |
| 225 http_path = os.path.join(examples_path, 'httpd.cmd') |
| 226 proc = subprocess.Popen([http_path], cwd=examples_path) |
| 227 else: |
| 228 http_path = os.path.join(examples_path, 'httpd.py') |
| 229 proc = subprocess.Popen(['python', http_path], cwd=examples_path) |
| 230 |
| 231 success = self.WaitUntil( |
| 232 lambda: self._IsURLAlive('http://localhost:5103'), |
| 233 timeout=30, retry_sleep=1, expect_retval=True) |
| 234 self.assertTrue(success, |
| 235 msg='Cannot open HTTP server. %s' % |
| 236 self.GetActiveTabTitle()) |
| 237 |
| 238 examples = { |
| 239 'hello_world_c': 'http://localhost:5103/hello_world_c/' |
| 240 'hello_world.html', |
| 241 'hello_world': 'http://localhost:5103/hello_world/hello_world.html', |
| 242 'geturl': 'http://localhost:5103/geturl/geturl.html', |
| 243 'pi_generator': 'http://localhost:5103/pi_generator/pi_generator.html', |
| 244 'sine_synth': 'http://localhost:5103/sine_synth/sine_synth.html', |
| 245 } |
| 246 try: |
| 247 self._OpenExamplesAndStartTest(examples) |
| 248 finally: |
| 249 self._CloseHTTPServer(proc) |
| 250 |
| 251 def _VerifyRebuildExamples(self): |
| 252 """Re-build the examples and verify they are as expected.""" |
| 253 examples_path = self._GetDirectoryPath('examples', |
| 254 self._extracted_sdk_path) |
| 255 scons_path = os.path.join(examples_path, 'scons -c') |
| 256 |
| 257 example_dirs = [ |
| 258 'geturl', |
| 259 'hello_world', |
| 260 'hello_world_c', |
| 261 'pi_generator', |
| 262 'sine_synth' |
| 263 ] |
| 264 |
| 265 proc = subprocess.Popen([scons_path], cwd=examples_path, shell=True) |
| 266 proc.communicate() |
| 267 for x in example_dirs: |
| 268 ex_path = os.path.join(examples_path, x) |
| 269 if self._HasFile('*.nmf', ex_path): |
| 270 self.fail(msg='Failed running scons -c.') |
| 271 |
| 272 scons_path = os.path.join(examples_path, 'scons') |
| 273 proc = subprocess.Popen([scons_path], cwd=examples_path, |
| 274 stdout=subprocess.PIPE, shell=True) |
| 275 proc.communicate() |
| 276 |
| 277 # Verify each example directory contains .nmf file. |
| 278 for dir in example_dirs: |
| 279 dir = os.path.join(examples_path, dir) |
| 280 if not self._HasFile('*.nmf', dir): |
| 281 self.fail(msg='Failed running scons.') |
| 282 |
| 283 self._LaunchServerAndVerifyExamples() |
| 284 |
| 285 def _VerifySelldrAndNcval(self): |
| 286 """Verify sel_ldr and ncval.""" |
| 287 architecture = self._GetPlatformArchitecture() |
| 288 scons_arg = None |
| 289 if pyauto.PyUITest.IsWin(): |
| 290 if architecture == '64bit': |
| 291 scons_arg = 'test64' |
| 292 else: |
| 293 scons_arg = 'test32' |
| 294 elif pyauto.PyUITest.IsMac(): |
| 295 scons_arg = 'test64' |
| 296 elif pyauto.PyUITest.IsLinux(): |
| 297 scons_arg = 'test64' |
| 298 |
| 299 examples_path = self._GetDirectoryPath('examples', |
| 300 self._extracted_sdk_path) |
| 301 scons_path = os.path.join(examples_path, 'scons ' + scons_arg) |
| 302 |
| 303 # Build and run the unit test. |
| 304 proc = subprocess.Popen([scons_path], stdout=subprocess.PIPE, |
| 305 shell=True, cwd=examples_path) |
| 306 stdout = proc.communicate()[0] |
| 307 lines = stdout.splitlines() |
| 308 test_ran = False |
| 309 for line in lines: |
| 310 if 'Check:' in line: |
| 311 self.assertTrue('passed' in line, |
| 312 msg='Nacl-sel_ldr unit test failed.') |
| 313 test_ran = True |
| 314 self.assertTrue(test_ran, |
| 315 msg='Failed to build and run nacl-sel_ldr unit test.') |
| 316 |
| 317 if architecture == '64bit': |
| 318 if not self._HasPathInTree('hello_world_x86_64.nexe', |
| 319 True, root=examples_path): |
| 320 self.fail(msg='Missing file: hello_world_x86_64.nexe.') |
| 321 else: |
| 322 if not self._HasPathInTree('hello_world_x86_32.nexe', |
| 323 True, root=examples_path): |
| 324 self.fail(msg='Missing file: hello_world_x86_32.nexe.') |
| 325 |
| 326 # Verify that a mismatch of sel_ldr and .nexe produces an error. |
| 327 toolchain_path = self._GetDirectoryPath('toolchain', |
| 328 self._extracted_sdk_path) |
| 329 bin_path = self._GetDirectoryPath('bin', toolchain_path) |
| 330 hello_world_path = self._GetDirectoryPath('hello_world', examples_path) |
| 331 sel_32_path = os.path.join(bin_path, 'sel_ldr_x86_32') |
| 332 sel_64_path = os.path.join(bin_path, 'sel_ldr_x86_64') |
| 333 nexe_32_path = os.path.join(hello_world_path, 'hello_world_x86_32.nexe') |
| 334 nexe_64_path = os.path.join(hello_world_path, 'hello_world_x86_64.nexe') |
| 335 |
| 336 if architecture == '64bit': |
| 337 success = self._RunProcessAndCheckOutput( |
| 338 [sel_64_path, nexe_32_path], 'Error while loading') |
| 339 else: |
| 340 success = self._RunProcessAndCheckOutput( |
| 341 [sel_32_path, nexe_64_path], 'Error while loading') |
| 342 self.assertTrue(success, |
| 343 msg='Failed to verify sel_ldr and .nexe mismatch.') |
| 344 |
| 345 # Run the appropriate ncval for the platform on the matching .nexe. |
| 346 ncval_32_path = os.path.join(bin_path, 'ncval_x86_32') |
| 347 ncval_64_path = os.path.join(bin_path, 'ncval_x86_64') |
| 348 |
| 349 if architecture == '64bit': |
| 350 success = self._RunProcessAndCheckOutput( |
| 351 [ncval_64_path, nexe_64_path], 'is safe') |
| 352 else: |
| 353 success = self._RunProcessAndCheckOutput( |
| 354 [ncval_32_path, nexe_32_path], 'is safe') |
| 355 self.assertTrue(success, msg='Failed to verify ncval.') |
| 356 |
| 357 # Verify that a mismatch of ncval and .nexe produces an error. |
| 358 if architecture == '64bit': |
| 359 success = self._RunProcessAndCheckOutput( |
| 360 [ncval_64_path, nexe_32_path], 'is safe', is_in=False) |
| 361 else: |
| 362 success = self._RunProcessAndCheckOutput( |
| 363 [ncval_32_path, nexe_64_path], 'is safe', is_in=False) |
| 364 self.assertTrue(success, msg='Failed to verify ncval and .nexe mismatch.') |
| 365 |
| 366 def _RemoveDownloadedTestFile(self): |
| 367 """Delete downloaded files and dirs from downloads directory.""" |
| 368 if os.path.exists(self._extracted_sdk_path): |
| 369 try: |
| 370 shutil.rmtree(self._extracted_sdk_path) |
| 371 except: |
| 372 self.fail(msg='Cannot remove %s' % self._extracted_sdk_path) |
| 373 |
| 374 for sdk in ['naclsdk_win.exe', 'naclsdk_mac.tgz', |
| 375 'naclsdk_linux.tgz']: |
| 376 sdk_path = os.path.join(self._download_dir, sdk) |
| 377 if os.path.exists(sdk_path): |
| 378 try: |
| 379 os.remove(sdk_path) |
| 380 except: |
| 381 self.fail(msg='Cannot remove %s' % sdk_path) |
| 382 |
| 383 def _RunProcessAndCheckOutput(self, args, look_for, is_in=True): |
| 384 """Run process and look for string in output. |
| 385 |
| 386 Args: |
| 387 args: Argument strings to pass to subprocess. |
| 388 look_for: The string to search in output. |
| 389 is_in: True if checking if param look_for is in output. |
| 390 False if checking if param look_for is not in output. |
| 391 |
| 392 Returns: |
| 393 True, if output contains parameter |look_for| and |is_in| is True, or |
| 394 False otherwise. |
| 395 """ |
| 396 proc = subprocess.Popen(args, stdout=subprocess.PIPE, |
| 397 stderr=subprocess.PIPE) |
| 398 (stdout, stderr) = proc.communicate() |
| 399 lines = stdout.splitlines() |
| 400 for line in lines: |
| 401 if look_for in line: |
| 402 return is_in |
| 403 |
| 404 lines = stderr.splitlines() |
| 405 for line in lines: |
| 406 if look_for in line: |
| 407 return is_in |
| 408 return not is_in |
| 409 |
| 410 def _OpenExamplesAndStartTest(self, examples): |
| 411 """Open each example and verify that it's working. |
| 412 |
| 413 Args: |
| 414 examples: A dict of name to url of examples. |
| 415 """ |
| 416 self._EnableNaClPlugin() |
| 417 |
| 418 # Open all examples. |
| 419 for name, url in examples.items(): |
| 420 self.AppendTab(pyauto.GURL(url)) |
| 421 self._CheckForCrashes() |
| 422 |
| 423 # Verify all examples are working. |
| 424 for name, url in examples.items(): |
| 425 self._VerifyAnExample(name, url) |
| 426 self._CheckForCrashes() |
| 427 |
| 428 # Reload all examples. |
| 429 for _ in range(2): |
| 430 for tab_index in range(self.GetTabCount()): |
| 431 self.GetBrowserWindow(0).GetTab(tab_index).Reload() |
| 432 self._CheckForCrashes() |
| 433 |
| 434 # Verify all examples are working. |
| 435 for name, url in examples.items(): |
| 436 self._VerifyAnExample(name, url) |
| 437 self._CheckForCrashes() |
| 438 |
| 439 # Close each tab, check for crashes and verify all open |
| 440 # examples operate correctly. |
| 441 tab_count = self.GetTabCount() |
| 442 for index in xrange(tab_count - 1, 0, -1): |
| 443 self.GetBrowserWindow(0).GetTab(index).Close(True) |
| 444 self._CheckForCrashes() |
| 445 |
| 446 tabs = self.GetBrowserInfo()['windows'][0]['tabs'] |
| 447 for tab in tabs: |
| 448 if tab['index'] > 0: |
| 449 for name, url in examples.items(): |
| 450 if url == tab['url']: |
| 451 self._VerifyAnExample(name, url) |
| 452 break |
| 453 |
| 454 def _VerifyAnExample(self, name, url): |
| 455 """Verify NaCl example is working. |
| 456 |
| 457 Args: |
| 458 name: A string name of the example. |
| 459 url: A string url of the example. |
| 460 """ |
| 461 available_example_tests = { |
| 462 'hello_world_c': self._VerifyHelloWorldExample, |
| 463 'hello_world': self._VerifyHelloWorldExample, |
| 464 'pi_generator': self._VerifyPiGeneratorExample, |
| 465 'sine_synth': self._VerifySineSynthExample, |
| 466 'geturl': self._VerifyGetURLExample, |
| 467 'life': self._VerifyConwaysLifeExample |
| 468 } |
| 469 |
| 470 if not name in available_example_tests: |
| 471 self.fail(msg='No test available for %s.' % name) |
| 472 |
| 473 info = self.GetBrowserInfo() |
| 474 tabs = info['windows'][0]['tabs'] |
| 475 tab_index = None |
| 476 for tab in tabs: |
| 477 if url == tab['url']: |
| 478 self.ActivateTab(tab['index']) |
| 479 tab_index = tab['index'] |
| 480 break |
| 481 |
| 482 if tab_index: |
| 483 available_example_tests[name](tab_index, name, url) |
| 484 |
| 485 def _VerifyHelloWorldExample(self, tab_index, name, url): |
| 486 """Verify Hello World Example. |
| 487 |
| 488 Args: |
| 489 tab_index: Tab index integer that the example is on. |
| 490 name: A string name of the example. |
| 491 url: A string url of the example. |
| 492 """ |
| 493 success = self.WaitUntil( |
| 494 lambda: self.GetDOMValue( |
| 495 'document.getElementById("statusField").innerHTML', |
| 496 0, tab_index), |
| 497 timeout=60, expect_retval='SUCCESS') |
| 498 self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url)) |
| 499 |
| 500 js_code = """ |
| 501 window.alert = function(e) { |
| 502 window.domAutomationController.send(String(e)); |
| 503 } |
| 504 window.domAutomationController.send("done"); |
| 505 """ |
| 506 self.ExecuteJavascript(js_code, 0, tab_index) |
| 507 |
| 508 result = self.ExecuteJavascript('document.helloForm.elements[1].click();', |
| 509 0, tab_index) |
| 510 self.assertEqual(result, '42', |
| 511 msg='Example %s failed. URL: %s' % (name, url)) |
| 512 |
| 513 result = self.ExecuteJavascript('document.helloForm.elements[2].click();', |
| 514 0, tab_index) |
| 515 self.assertEqual(result, 'dlrow olleH', |
| 516 msg='Example %s failed. URL: %s' % (name, url)) |
| 517 |
| 518 def _VerifyPiGeneratorExample(self, tab_index, name, url): |
| 519 """Verify Pi Generator Example. |
| 520 |
| 521 Args: |
| 522 tab_index: Tab index integer that the example is on. |
| 523 name: A string name of the example. |
| 524 url: A string url of the example. |
| 525 """ |
| 526 success = self.WaitUntil( |
| 527 lambda: self.GetDOMValue('document.form.pi.value', 0, tab_index)[0:3], |
| 528 timeout=120, expect_retval='3.1') |
| 529 self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url)) |
| 530 |
| 531 # Get top corner of Pi image. |
| 532 js_code = """ |
| 533 var obj = document.getElementById('piGenerator'); |
| 534 var curleft = curtop = 0; |
| 535 do { |
| 536 curleft += obj.offsetLeft; |
| 537 curtop += obj.offsetTop; |
| 538 } while (obj = obj.offsetParent); |
| 539 window.domAutomationController.send(curleft + "," + curtop); |
| 540 """ |
| 541 result = self.ExecuteJavascript(js_code, 0, tab_index) |
| 542 result_split = result.split(",") |
| 543 x = int(result_split[0]) |
| 544 y = int(result_split[1]) |
| 545 window = self.GetBrowserInfo()['windows'][0] |
| 546 window_to_content_x = 2 |
| 547 window_to_content_y = 80 |
| 548 pi_image_x = x + window['x'] + window_to_content_x |
| 549 pi_image_y = y + window['y'] + window_to_content_y |
| 550 |
| 551 if self._IsGetPixelSupported(): |
| 552 is_animating = self._IsColorChanging(pi_image_x, pi_image_y, 50, 50) |
| 553 self.assertTrue(is_animating, |
| 554 msg='Example %s failed. URL: %s' % (name, url)) |
| 555 |
| 556 def _VerifySineSynthExample(self, tab_index, name, url): |
| 557 """Verify Sine Wave Synthesizer Example. |
| 558 |
| 559 Args: |
| 560 tab_index: Tab index integer that the example is on. |
| 561 name: A string name of the example. |
| 562 url: A string url of the example. |
| 563 """ |
| 564 success = self.WaitUntil( |
| 565 lambda: self.GetDOMValue( |
| 566 'document.getElementById("frequency_field").value', |
| 567 0, tab_index), |
| 568 timeout=30, expect_retval='440') |
| 569 self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url)) |
| 570 |
| 571 self.ExecuteJavascript( |
| 572 'document.body.getElementsByTagName("button")[0].click();' |
| 573 'window.domAutomationController.send("done")', |
| 574 0, tab_index) |
| 575 |
| 576 # TODO(chrisphan): Verify sound. |
| 577 |
| 578 def _VerifyGetURLExample(self, tab_index, name, url): |
| 579 """Verify GetURL Example. |
| 580 |
| 581 Args: |
| 582 tab_index: Tab index integer that the example is on. |
| 583 name: A string name of the example. |
| 584 url: A string url of the example. |
| 585 """ |
| 586 success = self.WaitUntil( |
| 587 lambda: self.GetDOMValue( |
| 588 'document.getElementById("status_field").innerHTML', |
| 589 0, tab_index), |
| 590 timeout=60, expect_retval='SUCCESS') |
| 591 self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url)) |
| 592 |
| 593 self.ExecuteJavascript( |
| 594 'document.geturl_form.elements[0].click();' |
| 595 'window.domAutomationController.send("done")', |
| 596 0, tab_index) |
| 597 |
| 598 js_code = """ |
| 599 var output = document.getElementById("general_output").innerHTML; |
| 600 var result; |
| 601 if (output.indexOf("test passed") != -1) |
| 602 result = "pass"; |
| 603 else |
| 604 result = "fail"; |
| 605 window.domAutomationController.send(result); |
| 606 """ |
| 607 success = self.WaitUntil( |
| 608 lambda: self.ExecuteJavascript(js_code, 0, tab_index), |
| 609 timeout=30, expect_retval='pass') |
| 610 self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url)) |
| 611 |
| 612 def _VerifyConwaysLifeExample(self, tab_index, name, url): |
| 613 """Verify Conway's Life Example. |
| 614 |
| 615 Args: |
| 616 tab_index: Tab index integer that the example is on. |
| 617 name: A string name of the example. |
| 618 url: A string url of the example. |
| 619 """ |
| 620 window = self.GetBrowserInfo()['windows'][0] |
| 621 window_to_content_x = 2 |
| 622 window_to_content_y = 80 |
| 623 x = window['x'] + window_to_content_x |
| 624 y = window['y'] + window_to_content_y |
| 625 offset_pixel = 100 |
| 626 if self._IsGetPixelSupported(): |
| 627 success = self.WaitUntil( |
| 628 lambda: self._GetPixel(x + offset_pixel, y + offset_pixel), |
| 629 timeout=30, expect_retval=16777215) |
| 630 self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url)) |
| 631 |
| 632 def _IsColorChanging(self, x, y, width, height, tries=3, retry_sleep=2): |
| 633 """Check screen for anything that is moving. |
| 634 |
| 635 Args: |
| 636 x: X coordinate on the screen. |
| 637 y: Y coordinate on the screen. |
| 638 width: Width of the area to scan. |
| 639 height: Height of the area to scan. |
| 640 tries: Number of tries. |
| 641 retry_sleep: Sleep time in-between each try. |
| 642 |
| 643 Returns: |
| 644 True, if pixel color in area is changing, or |
| 645 False otherwise. |
| 646 """ |
| 647 color_a = self._GetAreaPixelColor(x, y, width, height) |
| 648 for _ in xrange(tries): |
| 649 time.sleep(retry_sleep) |
| 650 color_b = self._GetAreaPixelColor(x, y, width, height) |
| 651 if color_a != color_b: |
| 652 return True |
| 653 return False |
| 654 |
| 655 def _IsGetPixelSupported(self): |
| 656 """Check if get pixel is supported. |
| 657 |
| 658 Returns: |
| 659 True, if get pixel is supported, or |
| 660 False otherwise. |
| 661 """ |
| 662 return pyauto.PyUITest.IsWin() |
| 663 |
| 664 def _GetAreaPixelColor(self, x, y, width, height): |
| 665 """Get an area of pixel color and return a list of color code values. |
| 666 |
| 667 Args: |
| 668 x: X coordinate on the screen. |
| 669 y: Y coordinate on the screen. |
| 670 width: Width of the area to scan. |
| 671 height: Height of the area to scan. |
| 672 |
| 673 Returns: |
| 674 A list containing color codes. |
| 675 """ |
| 676 if pyauto.PyUITest.IsMac(): |
| 677 pass # TODO(chrisphan): Do Mac. |
| 678 elif pyauto.PyUITest.IsWin(): |
| 679 return self._GetAreaPixelColorWin(x, y, width, height) |
| 680 elif pyauto.PyUITest.IsLinux(): |
| 681 pass # TODO(chrisphan): Do Linux. |
| 682 return None |
| 683 |
| 684 def _GetAreaPixelColorWin(self, x, y, width, height): |
| 685 """Get an area of pixel color for Windows and return a list. |
| 686 |
| 687 Args: |
| 688 x: X coordinate on the screen. |
| 689 y: Y coordinate on the screen. |
| 690 width: Width of the area to scan. |
| 691 height: Height of the area to scan. |
| 692 |
| 693 Returns: |
| 694 A list containing color codes. |
| 695 """ |
| 696 colors = [] |
| 697 hdc = ctypes.windll.user32.GetDC(0) |
| 698 for x_pos in xrange(x, x + width, 1): |
| 699 for y_pos in xrange(y, y + height, 1): |
| 700 color = ctypes.windll.gdi32.GetPixel(hdc, x_pos, y_pos) |
| 701 colors.append(color) |
| 702 return colors |
| 703 |
| 704 def _GetPixel(self, x, y): |
| 705 """Get pixel color at coordinate x and y. |
| 706 |
| 707 Args: |
| 708 x: X coordinate on the screen. |
| 709 y: Y coordinate on the screen. |
| 710 |
| 711 Returns: |
| 712 An integer color code. |
| 713 """ |
| 714 if pyauto.PyUITest.IsMac(): |
| 715 pass # TODO(chrisphan): Do Mac. |
| 716 elif pyauto.PyUITest.IsWin(): |
| 717 return self._GetPixelWin(x, y) |
| 718 elif pyauto.PyUITest.IsLinux(): |
| 719 pass # TODO(chrisphan): Do Linux. |
| 720 return None |
| 721 |
| 722 def _GetPixelWin(self, x, y): |
| 723 """Get pixel color at coordinate x and y for Windows |
| 724 |
| 725 Args: |
| 726 x: X coordinate on the screen. |
| 727 y: Y coordinate on the screen. |
| 728 |
| 729 Returns: |
| 730 An integer color code. |
| 731 """ |
| 732 hdc = ctypes.windll.user32.GetDC(0) |
| 733 color = ctypes.windll.gdi32.GetPixel(hdc, x, y) |
| 734 return color |
| 735 |
| 736 def _CheckForCrashes(self, last_action=None, last_action_param=None): |
| 737 """Check for any browser/tab crashes and hangs. |
| 738 |
| 739 Args: |
| 740 last_action: Specify action taken before checking for crashes. |
| 741 last_action_param: Parameter for last action. |
| 742 """ |
| 743 self.assertTrue(self.GetBrowserWindowCount(), |
| 744 msg='Browser crashed, no window is open.') |
| 745 |
| 746 info = self.GetBrowserInfo() |
| 747 breakpad_folder = info['properties']['DIR_CRASH_DUMPS'] |
| 748 old_dmp_files = glob.glob(os.path.join(breakpad_folder, '*.dmp')) |
| 749 |
| 750 # Verify there're no crash dump files. |
| 751 for dmp_file in glob.glob(os.path.join(breakpad_folder, '*.dmp')): |
| 752 self.assertTrue(dmp_file in old_dmp_files, |
| 753 msg='Crash dump %s found' % dmp_file) |
| 754 |
| 755 # Check for any crashed tabs. |
| 756 tabs = info['windows'][0]['tabs'] |
| 757 for tab in tabs: |
| 758 if tab['url'] != 'about:blank': |
| 759 if not self.GetDOMValue('document.body.innerHTML', 0, tab['index']): |
| 760 self.fail(msg='Tab crashed on %s' % tab['url']) |
| 761 |
| 762 # TODO(chrisphan): Check for tab hangs and browser hangs. |
| 763 # TODO(chrisphan): Handle specific action: close browser, close tab. |
| 764 if last_action == 'close tab': |
| 765 pass |
| 766 elif last_action == 'close browser': |
| 767 pass |
| 768 else: |
| 769 pass |
| 770 |
| 771 def _GetPlatformArchitecture(self): |
| 772 """Get platform architecture. |
| 773 |
| 774 Args: |
| 775 last_action: Last action taken before checking for crashes. |
| 776 last_action_param: Parameter for last action. |
| 777 |
| 778 Returns: |
| 779 A string representing the platform architecture. |
| 780 """ |
| 781 if pyauto.PyUITest.IsWin(): |
| 782 if os.environ['PROGRAMFILES'] == 'C:\\Program Files (x86)': |
| 783 return '64bit' |
| 784 else: |
| 785 return '32bit' |
| 786 elif pyauto.PyUITest.IsMac() or pyauto.PyUITest.IsLinux(): |
| 787 if platform.machine() == 'x86_64': |
| 788 return '64bit' |
| 789 else: |
| 790 return '32bit' |
| 791 return '32bit' |
| 792 |
| 793 def _HasFile(self, pattern, root=os.curdir): |
| 794 """Check if a file matching the specified pattern exists in a directory. |
| 795 |
| 796 Args: |
| 797 pattern: Pattern of file name. |
| 798 root: Directory to start looking. |
| 799 |
| 800 Returns: |
| 801 True, if root contains the file name pattern, or |
| 802 False otherwise. |
| 803 """ |
| 804 return len(glob.glob(os.path.join(root, pattern))) |
| 805 |
| 806 def _HasPathInTree(self, pattern, is_file, root=os.curdir): |
| 807 """Recursively checks if a file/directory matching a pattern exists. |
| 808 |
| 809 Args: |
| 810 pattern: Pattern of file or directory name. |
| 811 is_file: True if looking for file, or False if looking for directory. |
| 812 root: Directory to start looking. |
| 813 |
| 814 Returns: |
| 815 True, if root contains the directory name pattern, or |
| 816 False otherwise. |
| 817 """ |
| 818 for path, dirs, files in os.walk(os.path.abspath(root)): |
| 819 if is_file: |
| 820 if len(fnmatch.filter(files, pattern)): |
| 821 return True |
| 822 else: |
| 823 if len(fnmatch.filter(dirs, pattern)): |
| 824 return True |
| 825 return False |
| 826 |
| 827 def _GetDirectoryPath(self, pattern, root=os.curdir): |
| 828 """Get the path of a directory in another directory. |
| 829 |
| 830 Args: |
| 831 pattern: Pattern of directory name. |
| 832 root: Directory to start looking. |
| 833 |
| 834 Returns: |
| 835 A string of the path. |
| 836 """ |
| 837 for path, dirs, files in os.walk(os.path.abspath(root)): |
| 838 result = fnmatch.filter(dirs, pattern) |
| 839 if len(result) > 0: |
| 840 return os.path.join(path, result[0]) |
| 841 return None |
| 842 |
| 843 def _HasAllSystemRequirements(self): |
| 844 """Verify NaCl SDK installation system requirements. |
| 845 |
| 846 Returns: |
| 847 True, if system passed requirements, or |
| 848 False otherwise. |
| 849 """ |
| 850 # Check python version. |
| 851 if sys.version_info[0:2] < (2, 5): |
| 852 return False |
| 853 |
| 854 # Check OS requirements. |
| 855 if pyauto.PyUITest.IsMac(): |
| 856 mac_min_version = version.StrictVersion('10.6') |
| 857 mac_version = version.StrictVersion(platform.mac_ver()[0]) |
| 858 if mac_version < mac_min_version: |
| 859 return False |
| 860 elif pyauto.PyUITest.IsWin(): |
| 861 if not (self.IsWin7() or self.IsWinVista() or self.IsWinXP()): |
| 862 return False |
| 863 elif pyauto.PyUITest.IsLinux(): |
| 864 pass # TODO(chrisphan): Check Lin requirements. |
| 865 else: |
| 866 return False |
| 867 |
| 868 # Check for Chrome version compatibility. |
| 869 # NaCl supports Chrome 10 and higher builds. |
| 870 settings = self._GetTestSetting() |
| 871 min_required_chrome_build = settings['min_required_chrome_build'] |
| 872 browser_info = self.GetBrowserInfo() |
| 873 chrome_version = browser_info['properties']['ChromeVersion'] |
| 874 chrome_build = int(chrome_version.split('.')[0]) |
| 875 return chrome_build >= min_required_chrome_build |
| 876 |
| 877 def _DownloadNaClSDK(self): |
| 878 """Download NaCl SDK.""" |
| 879 settings = self._GetTestSetting() |
| 880 |
| 881 if pyauto.PyUITest.IsWin(): |
| 882 dl_file = urllib2.urlopen(settings['release_win_sdk_url']) |
| 883 file_path = os.path.join(self._download_dir, 'naclsdk_win.exe') |
| 884 elif pyauto.PyUITest.IsMac(): |
| 885 dl_file = urllib2.urlopen(settings['release_mac_sdk_url']) |
| 886 file_path = os.path.join(self._download_dir, 'naclsdk_mac.tgz') |
| 887 elif pyauto.PyUITest.IsLinux(): |
| 888 dl_file = urllib2.urlopen(settings['release_lin_sdk_url']) |
| 889 file_path = os.path.join(self._download_dir, 'naclsdk_linux.tgz') |
| 890 else: |
| 891 self.fail(msg='NaCl SDK does not support this OS.') |
| 892 |
| 893 try: |
| 894 f = open(file_path, 'wb') |
| 895 f.write(dl_file.read()) |
| 896 except IOError: |
| 897 self.fail(msg='Cannot open %s.' % file_path) |
| 898 finally: |
| 899 f.close() |
| 900 |
| 901 def _ExtractNaClSDK(self): |
| 902 """Extract NaCl SDK.""" |
| 903 os.makedirs(self._extracted_sdk_path) |
| 904 |
| 905 if pyauto.PyUITest.IsWin(): |
| 906 # Requires 7-Zip to extract self-install archive. |
| 907 seven_z_file_path = self._GetWin7ZipPath() |
| 908 self.assertNotEqual(seven_z_file_path, None, |
| 909 '7-Zip is required but could not be found.') |
| 910 |
| 911 source_file = os.path.join(self._download_dir, 'naclsdk_win.exe') |
| 912 proc = subprocess.Popen( |
| 913 [seven_z_file_path, 'x', source_file, '-o' + |
| 914 self._extracted_sdk_path], |
| 915 stdout=subprocess.PIPE) |
| 916 proc.communicate() |
| 917 elif pyauto.PyUITest.IsMac(): |
| 918 source_file = os.path.join(self._download_dir, 'naclsdk_mac.tgz') |
| 919 tar = tarfile.open(source_file, 'r') |
| 920 tar.extractall(self._extracted_sdk_path) |
| 921 elif pyauto.PyUITest.IsLinux(): |
| 922 source_file = os.path.join(self._download_dir, 'naclsdk_linux.tgz') |
| 923 tar = tarfile.open(source_file, 'r') |
| 924 tar.extractall(self._extracted_sdk_path) |
| 925 else: |
| 926 self.fail(msg='NaCl SDK does not support this OS.') |
| 927 |
| 928 def _GetWin7ZipPath(self): |
| 929 """Check if 7-Zip is installed on Windows. |
| 930 |
| 931 Returns: |
| 932 String path to the 7-Zip executable, or None if it cannot be found. |
| 933 """ |
| 934 current_dir = os.path.dirname(__file__) |
| 935 seven_zip_path = os.path.join( |
| 936 current_dir, os.pardir, os.pardir, |
| 937 os.pardir, 'third_party', '7-Zip', '7z.exe') |
| 938 |
| 939 if os.path.isfile(seven_zip_path): |
| 940 return seven_zip_path |
| 941 |
| 942 # Attempt to find 7-Zip in Program Files. |
| 943 program_files_path = os.getenv('ProgramFiles') |
| 944 if program_files_path != None: |
| 945 seven_zip_path = os.path.join(program_files_path, '7-Zip', '7z.exe') |
| 946 if os.path.isfile(seven_zip_path): |
| 947 return seven_zip_path |
| 948 program_files_path = os.getenv('ProgramW6432') |
| 949 if program_files_path != None: |
| 950 seven_zip_path = os.path.join(program_files_path, '7-Zip', '7z.exe') |
| 951 if os.path.isfile(seven_zip_path): |
| 952 return seven_zip_path |
| 953 |
| 954 return None |
| 955 |
| 956 def _IsURLAlive(self, url): |
| 957 """Test if URL is alive.""" |
| 958 try: |
| 959 urllib2.urlopen(url) |
| 960 except: |
| 961 return False |
| 962 return True |
| 963 |
| 964 def _CloseHTTPServer(self, proc=None): |
| 965 """Close HTTP server. |
| 966 |
| 967 Args: |
| 968 proc: Process that opened the HTTP server. |
| 969 """ |
| 970 if not self._IsURLAlive('http://localhost:5103'): |
| 971 return |
| 972 response = urllib2.urlopen('http://localhost:5103') |
| 973 html = response.read() |
| 974 if not 'Native Client' in html: |
| 975 self.fail(msg='Port 5103 is in use.') |
| 976 |
| 977 urllib2.urlopen('http://localhost:5103?quit=1') |
| 978 success = self.WaitUntil( |
| 979 lambda: self._IsURLAlive('http://localhost:5103'), |
| 980 timeout=30, expect_retval=False) |
| 981 if not success: |
| 982 if proc == None: |
| 983 self.fail(msg='Fail to close HTTP server.') |
| 984 else: |
| 985 if proc.poll() == None: |
| 986 try: |
| 987 proc.kill() |
| 988 except: |
| 989 self.fail(msg='Failed to close HTTP server') |
| 990 |
| 991 def _SearchNaClSDKTarFile(self, search_list, source_file): |
| 992 """Search NaCl SDK tar file for example files and directories. |
| 993 |
| 994 Args: |
| 995 search_list: A list of strings, representing file and |
| 996 directory names for which to search. |
| 997 source_file: The string name of an NaCl SDK tar file. |
| 998 """ |
| 999 tar = tarfile.open(source_file, 'r') |
| 1000 |
| 1001 # Look for files and directories in examples. |
| 1002 files = copy.deepcopy(search_list) |
| 1003 for tar_info in tar: |
| 1004 file_name = tar_info.name |
| 1005 if tar_info.isdir() and not file_name.endswith('/'): |
| 1006 file_name = file_name + '/' |
| 1007 |
| 1008 for name in files: |
| 1009 if file_name.find('examples/' + name): |
| 1010 files.remove(name) |
| 1011 if len(files) == 0: |
| 1012 break |
| 1013 |
| 1014 tar.close() |
| 1015 |
| 1016 self.assertEqual(len(files), 0, |
| 1017 msg='Missing files or directories: %s' % |
| 1018 ', '.join(map(str, files))) |
| 1019 |
| 1020 def _SearchNaClSDKFileWindows(self, search_list, source_file): |
| 1021 """Search NaCl SDK file for example files and directories in Windows. |
| 1022 |
| 1023 Args: |
| 1024 search_list: A list of strings, representing file and |
| 1025 directory names for which to search. |
| 1026 source_file: The string name of an NaCl SDK Windows |
| 1027 self-install archive file. |
| 1028 """ |
| 1029 files = [] |
| 1030 for i in xrange(len(search_list)): |
| 1031 files.append(search_list[i].replace(r'/', '\\')) |
| 1032 |
| 1033 # Requires 7-Zip to look at self-install archive. |
| 1034 seven_z_file_path = self._GetWin7ZipPath() |
| 1035 self.assertNotEqual(seven_z_file_path, None, |
| 1036 msg='7-Zip is required but could not be found.') |
| 1037 |
| 1038 proc = subprocess.Popen([seven_z_file_path, 'l', source_file], |
| 1039 stdout=subprocess.PIPE) |
| 1040 stdout = proc.communicate()[0] |
| 1041 lines = stdout.splitlines() |
| 1042 for x in lines: |
| 1043 item_name = x.split(' ')[-1] |
| 1044 for name in files: |
| 1045 if item_name.find(name) > 0: |
| 1046 files.remove(name) |
| 1047 if len(files) == 0: |
| 1048 break |
| 1049 |
| 1050 self.assertEqual(len(files), 0, |
| 1051 msg='Missing files or directories: %s' % |
| 1052 ', '.join(map(str, files))) |
| 1053 |
| 1054 def _EnableNaClPlugin(self): |
| 1055 """"Enable NaCl plugin.""" |
| 1056 nacl_plugin = self.GetPluginsInfo().PluginForName('Chrome NaCl') |
| 1057 if not len(nacl_plugin): |
| 1058 nacl_plugin = self.GetPluginsInfo().PluginForName('Native Client') |
| 1059 if not len(nacl_plugin): |
| 1060 self.fail(msg='No NaCl plugin found.') |
| 1061 self.EnablePlugin(nacl_plugin[0]['path']) |
| 1062 |
| 1063 self.NavigateToURL('about:flags') |
| 1064 |
| 1065 js_code = """ |
| 1066 chrome.send('enableFlagsExperiment', ['enable-nacl', 'true']); |
| 1067 requestFlagsExperimentsData(); |
| 1068 window.domAutomationController.send('done'); |
| 1069 """ |
| 1070 self.ExecuteJavascript(js_code) |
| 1071 self.RestartBrowser(False) |
| 1072 |
| 1073 def _GetTestSetting(self): |
| 1074 """Read the given data file and return a dictionary of items. |
| 1075 |
| 1076 Returns: |
| 1077 A dict mapping of keys/values in the NaCl SDK setting file. |
| 1078 """ |
| 1079 data_file = os.path.join(self.DataDir(), 'nacl_sdk', 'nacl_sdk_setting') |
| 1080 |
| 1081 try: |
| 1082 f = open(data_file, 'r') |
| 1083 except IOError: |
| 1084 self.fail(msg='Cannot open %s.' % data_file) |
| 1085 |
| 1086 try: |
| 1087 dictionary = eval(f.read(), {'__builtins__': None}, None) |
| 1088 except SyntaxError: |
| 1089 self.fail(msg='%s is an invalid setting file.' % data_file) |
| 1090 finally: |
| 1091 f.close() |
| 1092 |
| 1093 return dictionary |
| 1094 |
| 1095 |
| 1096 if __name__ == '__main__': |
| 1097 pyauto_functional.Main() |
OLD | NEW |