Home | History | Annotate | Download | only in functional
      1 #!/usr/bin/env python
      2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
      3 # Use of this source code is governed by a BSD-style license that can be
      4 # found in the LICENSE file.
      5 
      6 import 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 re
     16 import shutil
     17 import subprocess
     18 import sys
     19 import tempfile
     20 import urllib2
     21 import xml.dom.minidom
     22 import zipfile
     23 
     24 import pyauto_functional  # Must be imported before pyauto.
     25 import pyauto
     26 import pyauto_utils
     27 import test_utils
     28 
     29 
     30 class NaClSDKTest(pyauto.PyUITest):
     31   """Tests for the NaCl SDK."""
     32   _isExamplesTest = False
     33   _extracted_sdk_path = None
     34   _temp_dir = None
     35   _updated_pepper_versions = []
     36   _latest_updated_pepper_versions = []
     37   _settings = {
     38       'post_sdk_download_url': 'http://code.google.com/chrome/nativeclient/'
     39           'docs/download.html',
     40       'post_sdk_zip': 'http://storage.googleapis.com/'
     41           'nativeclient-mirror/nacl/nacl_sdk/nacl_sdk.zip',
     42       'min_required_chrome_build': 14,
     43   }
     44 
     45   def tearDown(self):
     46     pyauto.PyUITest.tearDown(self)
     47     if not self._isExamplesTest:
     48       self._RemoveDownloadedTestFile()
     49 
     50   def testNaClSDK(self):
     51     """Verify that NaCl SDK is working properly."""
     52     if not self._HasAllSystemRequirements():
     53       logging.info('System does not meet the requirements.')
     54       return
     55     self._extracted_sdk_path = tempfile.mkdtemp()
     56     self._VerifyDownloadLinks()
     57     self._VerifyNaClSDKInstaller()
     58     self._VerifyInstall()
     59     self._VerifyUpdate()
     60     self._LaunchServerAndVerifyExamplesAllPepperVersions()
     61 
     62   def NaClSDKExamples(self):
     63     """Verify if NaCl SDK examples are working."""
     64     self._isExamplesTest = True
     65     nacl_sdk_root = os.environ.get('NACL_SDK_ROOT', None)
     66     pepper_version = os.environ.get('PEPPER_VER', None)
     67     if nacl_sdk_root and pepper_version:
     68       self._LaunchServerAndVerifyExamples('pepper_' + pepper_version,
     69           nacl_sdk_root)
     70     else:
     71       self.fail(msg='Missing pepper version to be checked or SDK path.')
     72 
     73   def _VerifyDownloadLinks(self):
     74     """Verify the download links.
     75 
     76     Simply verify that NaCl download links exist in html page.
     77     """
     78     html = None
     79     for i in xrange(3):
     80       try:
     81         html = urllib2.urlopen(self._settings['post_sdk_download_url']).read()
     82         break
     83       except:
     84         pass
     85     self.assertTrue(html,
     86                     msg='Cannot open URL: %s' %
     87                     self._settings['post_sdk_download_url'])
     88     sdk_url = self._settings['post_sdk_zip']
     89     self.assertTrue(sdk_url in html,
     90                     msg='Missing SDK download URL: %s' % sdk_url)
     91 
     92   def _VerifyNaClSDKInstaller(self):
     93     """Verify NaCl SDK installer."""
     94     search_list = [
     95         'sdk_cache/',
     96         'sdk_tools/',
     97     ]
     98     mac_lin_additional_search_items = [
     99         'naclsdk',
    100     ]
    101     win_additional_search_items = [
    102         'naclsdk.bat'
    103     ]
    104     self._DownloadNaClSDK()
    105     self._ExtractNaClSDK()
    106     if pyauto.PyUITest.IsWin():
    107       self._SearchNaClSDKFile(
    108           search_list + win_additional_search_items)
    109     elif pyauto.PyUITest.IsMac() or pyauto.PyUITest.IsLinux():
    110       self._SearchNaClSDKFile(
    111           search_list + mac_lin_additional_search_items)
    112     else:
    113       self.fail(msg='NaCl SDK does not support this OS.')
    114 
    115   def _VerifyInstall(self):
    116     """Install NACL sdk."""
    117     # Executing naclsdk(.bat) list
    118     if pyauto.PyUITest.IsWin():
    119       source_file = os.path.join(
    120           self._extracted_sdk_path, 'nacl_sdk', 'naclsdk.bat')
    121     elif pyauto.PyUITest.IsMac() or pyauto.PyUITest.IsLinux():
    122       source_file = os.path.join(
    123           self._extracted_sdk_path, 'nacl_sdk', 'naclsdk')
    124       subprocess.call(['chmod', '-R', '755', self._extracted_sdk_path])
    125     else:
    126       self.fail(msg='NaCl SDK does not support this OS.')
    127     subprocess.Popen([source_file, 'list'],
    128                      stdout=subprocess.PIPE,
    129                      stderr=subprocess.PIPE).communicate()
    130 
    131   def _VerifyUpdate(self):
    132     """Update NACL sdk"""
    133     # Executing naclsdk(.bat) update
    134     if pyauto.PyUITest.IsWin():
    135       source_file = os.path.join(self._extracted_sdk_path, 'nacl_sdk',
    136                                  'naclsdk.bat')
    137     elif pyauto.PyUITest.IsMac() or pyauto.PyUITest.IsLinux():
    138       source_file = os.path.join(self._extracted_sdk_path, 'nacl_sdk',
    139                                  'naclsdk')
    140     else:
    141       self.fail(msg='NaCl SDK does not support this OS.')
    142     # Executing nacl_sdk(.bat) update to get the latest version.
    143     updated_output = subprocess.Popen([source_file, 'update'],
    144         stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
    145     self._updated_pepper_versions.extend(
    146         re.findall('Updating bundle (pepper_[0-9]{2})', updated_output))
    147     self._updated_pepper_versions = list(set(self._updated_pepper_versions))
    148     self._updated_pepper_versions.sort(key=str.lower)
    149     updated_pepper_versions_len = len(self._updated_pepper_versions)
    150     self._latest_updated_pepper_versions = filter(
    151         lambda x: x >= 'pepper_18', self._updated_pepper_versions)
    152 
    153   def _GetURLForExampleName(self, name, toolchain):
    154     return 'http://localhost:5103/%s/index_%s.html' % (name, toolchain)
    155 
    156   def _GetExampleNamesAndURLs(self, examples_path):
    157     """Get a list of all examples as (name, url) tuples.
    158 
    159     Args:
    160       examples_path: The path to the examples directory in the NaCl SDK.
    161     """
    162     toolchains = ['newlib', 'glibc', 'pnacl']
    163 
    164     examples = []
    165     for toolchain in toolchains:
    166       for example in os.listdir(examples_path):
    167         html_path = os.path.join(examples_path, example,
    168             'index_%s.html' % (toolchain,))
    169         if os.path.exists(html_path):
    170           example_url = self._GetURLForExampleName(example, toolchain)
    171           examples.append((example, example_url))
    172     return examples
    173 
    174   def _LaunchServerAndVerifyExamplesAllPepperVersions(self):
    175     for pepper_version in self._latest_updated_pepper_versions:
    176       pepper_path = os.path.join(self._extracted_sdk_path,
    177           'nacl_sdk', 'pepper_' + str(pepper_version))
    178       self._LaunchServerAndVerifyExamples(pepper_version, pepper_path)
    179 
    180   def _LaunchServerAndVerifyExamples(self, pepper_version, pepper_path):
    181     """Start local HTTP server and verify examples."""
    182     if self._ChromeAndPepperVersionMatch(pepper_version):
    183       # Close server if it's already open.
    184       if self._IsURLAlive('http://localhost:5103'):
    185         self._CloseHTTPServer()
    186 
    187       examples_path = os.path.join(pepper_path, 'examples')
    188 
    189       # Launch local http server.
    190       proc = subprocess.Popen(['make RUN'], shell=True, cwd=examples_path)
    191       self.WaitUntil(
    192           lambda: self._IsURLAlive('http://localhost:5103'),
    193           timeout=150, retry_sleep=1)
    194 
    195       examples = self._GetExampleNamesAndURLs(examples_path)
    196       try:
    197         self._OpenExamplesAndStartTest(examples)
    198       finally:
    199         self._CloseHTTPServer(proc)
    200 
    201     else:
    202       self.pprint('Pepper Version %s does not match the Chrome version %s.'
    203           % (pepper_version,
    204           self.GetBrowserInfo()['properties']['ChromeVersion']))
    205 
    206   def _ChromeAndPepperVersionMatch(self, pepper_version='pepper_18'):
    207     """Determine if chrome and pepper version match"""
    208     version_number = re.findall('pepper_([0-9]{2})', pepper_version)
    209     browser_info = self.GetBrowserInfo()
    210     chrome_version = browser_info['properties']['ChromeVersion']
    211     chrome_build = int(chrome_version.split('.')[0])
    212     return int(chrome_build) == int(version_number[0])
    213 
    214   def _RemoveDownloadedTestFile(self):
    215     """Delete downloaded files and dirs from downloads directory."""
    216     if self._extracted_sdk_path and os.path.exists(self._extracted_sdk_path):
    217       self._CloseHTTPServer()
    218 
    219       def _RemoveFile():
    220         shutil.rmtree(self._extracted_sdk_path, ignore_errors=True)
    221         return os.path.exists(self._extracted_sdk_path)
    222 
    223       success = self.WaitUntil(_RemoveFile, retry_sleep=2,
    224                                expect_retval=False)
    225       self.assertTrue(success,
    226                       msg='Cannot remove %s' % self._extracted_sdk_path)
    227 
    228     if self._temp_dir:
    229       pyauto_utils.RemovePath(self._temp_dir)
    230 
    231   def _OpenExamplesAndStartTest(self, examples):
    232     """Open each example and verify that it's working.
    233 
    234     Args:
    235       examples: A list of example (name, url) tuples.
    236     """
    237     example_verify_funcs = {
    238         'dlopen': self._VerifyDynamicLibraryOpen,
    239         'file_io': self._VerifyFileIoExample,
    240         'geturl': self._VerifyGetURLExample,
    241         'input_events': self._VerifyInputEventsExample,
    242         'load_progress': self._VerifyLoadProgressExample,
    243         'mt_input_events': self._VerifyMultithreadedInputEventsExample,
    244         'pi_generator': self._VerifyPiGeneratorExample,
    245         'sine_synth': self._VerifySineSynthExample,
    246         'websocket': self._VerifyWebSocketExample,
    247     }
    248 
    249     # Remove examples that we don't yet verify
    250     examples = [(name, url) for name, url in examples
    251         if name in example_verify_funcs]
    252 
    253     # Open all examples.
    254     for name, url in examples:
    255       self.AppendTab(pyauto.GURL(url))
    256       self._CheckForCrashes()
    257 
    258     # Verify all examples are working.
    259     for name, url in examples:
    260       self._VerifyAnExample(name, url, example_verify_funcs[name])
    261     self._CheckForCrashes()
    262 
    263     # Close each tab and check for crashes.
    264     tab_count = self.GetTabCount()
    265     for index in xrange(tab_count - 1, 0, -1):
    266       self.CloseTab(tab_index=index)
    267       self._CheckForCrashes()
    268 
    269   def _VerifyAnExample(self, name, url, verify_func):
    270     """Verify NaCl example is working.
    271 
    272     Args:
    273       name: A string name of the example.
    274       url: A string url of the example.
    275       verify_func: The function to verify the example.
    276           Takes (tab_index, name, url) as parameters.
    277     """
    278     if not verify_func:
    279       self.fail(msg='No test available for %s.' % name)
    280 
    281     info = self.GetBrowserInfo()
    282     tabs = info['windows'][0]['tabs']
    283     tab_index = None
    284     for tab in tabs:
    285       if url == tab['url']:
    286         self.ActivateTab(tab['index'])
    287         tab_index = tab['index']
    288         break
    289 
    290     if tab_index:
    291       verify_func(tab_index, name, url)
    292 
    293   def _VerifyElementPresent(self, element_id, expected_value, tab_index, msg,
    294                             attribute='innerHTML', timeout=150):
    295     """Determine if dom element has the expected value.
    296 
    297     Args:
    298       element_id: Dom element's id.
    299       expected_value: String to be matched against the Dom element.
    300       tab_index: Tab index to work on.
    301       attribute: Attribute to match |expected_value| against, if
    302                  given. Defaults to 'innerHTML'.
    303       timeout: The max timeout (in secs) for which to wait.
    304     """
    305     js_code = """
    306         var output = document.getElementById('%s').%s;
    307         var result;
    308         if (output.indexOf('%s') != -1)
    309           result = 'pass';
    310         else
    311           result = 'fail';
    312         window.domAutomationController.send(result);
    313     """ % (element_id, attribute, expected_value)
    314     success = self.WaitUntil(
    315         lambda: self.ExecuteJavascript(js_code, tab_index),
    316         timeout=timeout, expect_retval='pass')
    317     self.assertTrue(success, msg=msg)
    318 
    319   def _CreateJSToSimulateMouseclick(self):
    320     """Create javascript to simulate mouse click event."""
    321     js_code = """
    322         var rightClick = document.createEvent('MouseEvents');
    323         rightClick.initMouseEvent(
    324           'mousedown', true, true, document,
    325           1, 32, 121, 10, 100,
    326           false, false, false, false,
    327           2, common.naclModule
    328         );
    329         common.naclModule.dispatchEvent(rightClick);
    330         window.domAutomationController.send('done');
    331     """
    332     return js_code
    333 
    334   def _VerifyInputEventsExample(self, tab_index, name, url):
    335     """Verify Input Events Example.
    336 
    337     Args:
    338       tab_index: Tab index integer that the example is on.
    339       name: A string name of the example.
    340       url: A string url of the example.
    341     """
    342     success = self._VerifyElementPresent('eventString', 'DidChangeView',
    343         tab_index, msg='Example %s failed. URL: %s' % (name, url))
    344 
    345     # Simulate mouse click on event module.
    346     js_code = self._CreateJSToSimulateMouseclick()
    347     self.ExecuteJavascript(js_code, tab_index)
    348 
    349     # Check if 'eventString' has handled above mouse click.
    350     success = self.WaitUntil(
    351         lambda: re.search('DidHandleInputEvent', self.GetDOMValue(
    352           'document.getElementById("eventString").innerHTML',
    353           tab_index)).group(), expect_retval='DidHandleInputEvent')
    354     self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
    355 
    356   def _VerifyMultithreadedInputEventsExample(self, tab_index, name, url):
    357     """Verify Input Events Example.
    358 
    359     Args:
    360       tab_index: Tab index integer that the example is on.
    361       name: A string name of the example.
    362       url: A string url of the example.
    363     """
    364     success = self.WaitUntil(
    365         lambda: bool(self.GetDOMValue(
    366           'document.getElementById("eventString").innerHTML',
    367           tab_index).find('DidChangeView') + 1))
    368 
    369     self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
    370 
    371     # Simulate mouse click on event module.
    372     js_code = self._CreateJSToSimulateMouseclick()
    373     self.ExecuteJavascript(js_code, tab_index)
    374 
    375     # Check if above mouse click is handled.
    376     success = self._VerifyElementPresent('eventString', 'Mouse event',
    377         tab_index, msg='Example %s failed. URL: %s' % (name, url))
    378 
    379     # Kill worker thread and queue
    380     js_code = """
    381       document.getElementsByTagName('button')[0].click();
    382       window.domAutomationController.send('done');
    383     """
    384     self.ExecuteJavascript(js_code, tab_index)
    385 
    386     # Check if main thread has cancelled queue.
    387     success = self._VerifyElementPresent('eventString', 'Received cancel',
    388         tab_index, msg='Example %s failed. URL: %s' % (name, url))
    389 
    390     # Simulate mouse click on event module.
    391     js_code = self._CreateJSToSimulateMouseclick()
    392     self.ExecuteJavascript(js_code, tab_index)
    393 
    394     # Check if above mouse click is not handled after killing worker thread.
    395     def _CheckMouseClickEventStatus():
    396       return self.GetDOMValue(
    397         'document.getElementById("eventString").innerHTML',
    398         tab_index).find('Mouse event', self.GetDOMValue(
    399         'document.getElementById("eventString").innerHTML', tab_index).find(
    400         'Received cancel'))
    401 
    402     success = self.WaitUntil(_CheckMouseClickEventStatus, expect_retval=-1)
    403     self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
    404 
    405   def _VerifyFileIoExample(self, tab_index, name, url):
    406     """Verify File IO Example.
    407 
    408     Args:
    409       tab_index: Tab index integer that the example is on.
    410       name: A string name of the example.
    411       url: A string url of the example.
    412     """
    413     def _CheckStatus(substring_expected, fail_msg):
    414       self.assertTrue(
    415           self.WaitUntil(
    416             lambda: self.GetDOMValue(
    417               'document.getElementById("statusField").innerHTML', tab_index)\
    418                   .find(substring_expected) != -1, expect_retval=True),
    419           msg='Example %s failed. URL: %s. Reason: %s' % (name, url, fail_msg))
    420 
    421     # Give permission to use file system by clicking infobar OK
    422     infobar_index = test_utils.WaitForInfobarTypeAndGetIndex(self,
    423         'confirm_infobar', 0, tab_index)
    424     self.PerformActionOnInfobar('accept', infobar_index, 0, tab_index)
    425     _CheckStatus('Ready!', 'NaCl module load')
    426 
    427     # Check that deleting non-existing files gives file not found
    428     js_code = """
    429       document.getElementById('file_name').value = '/abc';
    430       document.getElementById('file_editor').value = 'test';
    431       document.getElementById('delete_but').click();
    432       window.domAutomationController.send('done');
    433     """
    434     self.ExecuteJavascript(js_code, tab_index)
    435     _CheckStatus('File not found', 'Delete non-existing')
    436 
    437     # Check that saving works
    438     js_code = """
    439       document.getElementById('save_but').click();
    440       window.domAutomationController.send('done');
    441     """
    442     self.ExecuteJavascript(js_code, tab_index)
    443     _CheckStatus('Save successful', 'Save test')
    444 
    445     # Check that we load what we saved
    446     js_code = """
    447       document.getElementById('file_editor').value = 'different';
    448       document.getElementById('load_but').click();
    449       window.domAutomationController.send('done');
    450     """
    451     self.ExecuteJavascript(js_code, tab_index)
    452     _CheckStatus('Load complete', 'Load test')
    453     self.assertTrue(
    454         self.GetDOMValue('document.getElementById("file_editor").value',
    455           tab_index).find('test') != -1, msg='Loaded wrong text or failed')
    456 
    457     # Check that we delete files successfully
    458     js_code = """
    459       document.getElementById('delete_but').click();
    460       window.domAutomationController.send('done');
    461     """
    462     self.ExecuteJavascript(js_code, tab_index)
    463     _CheckStatus('File deleted', 'Delete test')
    464 
    465     # Check that file is deleted and load produces not found
    466     js_code = """
    467       document.getElementById('load_but').click();
    468       window.domAutomationController.send('done');
    469     """
    470     self.ExecuteJavascript(js_code, tab_index)
    471     _CheckStatus('File not found', 'Load deleted test')
    472 
    473   def _VerifyWebSocketExample(self, tab_index, name, url):
    474     """Verify Web Socket Open Example.
    475 
    476     Args:
    477       tab_index: Tab index integer that the example is on.
    478       name: A string name of the example.
    479       url: A string url of the example.
    480     """
    481     # Check if example is loaded.
    482     success = self.WaitUntil(
    483         lambda: self.GetDOMValue(
    484             'document.getElementById("statusField").innerHTML', tab_index),
    485             expect_retval='SUCCESS')
    486     self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
    487 
    488     # Simulate clicking on Connect button to establish a connection.
    489     js_code = """
    490       document.getElementsByTagName('input')[1].click();
    491       window.domAutomationController.send('done');
    492     """
    493     self.ExecuteJavascript(js_code, tab_index)
    494 
    495     # Check if connected
    496     success = self._VerifyElementPresent('log', 'connected', tab_index,
    497         msg='Example %s failed. URL: %s' % (name, url))
    498 
    499     # Simulate clicking on Send button to send text message in log.
    500     js_code = """
    501       document.getElementsByTagName('input')[3].click();
    502       window.domAutomationController.send('done');
    503     """
    504     self.ExecuteJavascript(js_code, tab_index)
    505     success = self.WaitUntil(
    506         lambda: bool(re.search('send:', self.GetDOMValue(
    507             'document.getElementById("log").textContent', tab_index))))
    508     self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
    509 
    510   def _VerifyDynamicLibraryOpen(self, tab_index, name, url):
    511     """Verify Dynamic Library Open Example.
    512 
    513     Args:
    514       tab_index: Tab index integer that the example is on.
    515       name: A string name of the example.
    516       url: A string url of the example.
    517     """
    518     # Check if example is loaded.
    519     success = self._VerifyElementPresent('log', 'Eightball loaded!',
    520         tab_index, msg='Example %s failed. URL: %s' % (name, url))
    521 
    522     # Simulate clicking on ASK button and check answer log for desired answer.
    523     js_code = """
    524       document.getElementsByTagName('input')[1].click();
    525       window.domAutomationController.send('done');
    526     """
    527     self.ExecuteJavascript(js_code, tab_index)
    528     def _CheckAnswerLog():
    529       return bool(re.search(r'NO|YES|42|MAYBE NOT|DEFINITELY|'
    530         'ASK ME TOMORROW|MAYBE|PARTLY CLOUDY',
    531         self.GetDOMValue('document.getElementById("log").innerHTML',
    532         tab_index)))
    533 
    534     success = self.WaitUntil(_CheckAnswerLog)
    535     self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
    536 
    537   def _VerifyLoadProgressExample(self, tab_index, name, url):
    538     """Verify Dynamic Library Open Example.
    539 
    540     Args:
    541       tab_index: Tab index integer that the example is on.
    542       name: A string name of the example.
    543       url: A string url of the example.
    544     """
    545     # Check if example loads and displays loading progress.
    546     success = self.WaitUntil(
    547         lambda: self.GetDOMValue(
    548         'document.getElementById("statusField").innerHTML', tab_index),
    549         timeout=150, expect_retval='SUCCESS')
    550     self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
    551 
    552     def _CheckLoadProgressStatus():
    553       return re.search(
    554           r'(loadstart).+(progress:).+(load).+(loadend).+(lastError:)',
    555           self.GetDOMValue(
    556           'document.getElementById("log").innerHTML', tab_index))
    557     success = self.WaitUntil(_CheckLoadProgressStatus)
    558     self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
    559 
    560   def _VerifyPiGeneratorExample(self, tab_index, name, url):
    561     """Verify Pi Generator Example.
    562 
    563     Args:
    564       tab_index: Tab index integer that the example is on.
    565       name: A string name of the example.
    566       url: A string url of the example.
    567     """
    568     success = self.WaitUntil(
    569         lambda: self.GetDOMValue('document.getElementById("pi").value',
    570             tab_index)[0:3],
    571         expect_retval='3.1')
    572     self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
    573 
    574   def _VerifySineSynthExample(self, tab_index, name, url):
    575     """Verify Sine Wave Synthesizer Example.
    576 
    577     Args:
    578       tab_index: Tab index integer that the example is on.
    579       name: A string name of the example.
    580       url: A string url of the example.
    581     """
    582     success = self.WaitUntil(
    583         lambda: self.GetDOMValue(
    584                     'document.getElementById("frequency_field").value',
    585                     tab_index), timeout=150, expect_retval='440')
    586     self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
    587     self.ExecuteJavascript(
    588         'document.body.getElementsByTagName("button")[0].click();'
    589         'window.domAutomationController.send("done")',
    590         tab_index)
    591 
    592   def _VerifyGetURLExample(self, tab_index, name, url):
    593     """Verify GetURL Example.
    594 
    595     Args:
    596       tab_index: Tab index integer that the example is on.
    597       name: A string name of the example.
    598       url: A string url of the example.
    599     """
    600     success = self.WaitUntil(
    601         lambda: self.GetDOMValue(
    602                     'document.getElementById("statusField").innerHTML',
    603                     tab_index), timeout=150, expect_retval='SUCCESS')
    604     self.assertTrue(success, msg='Example %s failed. URL: %s' % (name, url))
    605     self.ExecuteJavascript(
    606         'document.getElementById("button").click();'
    607         'window.domAutomationController.send("done")',
    608         tab_index)
    609     success = self._VerifyElementPresent('general_output', 'test passed',
    610         tab_index, msg='Example %s failed. URL: %s' % (name, url))
    611 
    612   def _CheckForCrashes(self):
    613     """Check for any browser/tab crashes and hangs."""
    614     self.assertTrue(self.GetBrowserWindowCount(),
    615                     msg='Browser crashed, no window is open.')
    616 
    617     info = self.GetBrowserInfo()
    618     breakpad_folder = info['properties']['DIR_CRASH_DUMPS']
    619     old_dmp_files = glob.glob(os.path.join(breakpad_folder, '*.dmp'))
    620 
    621     # Verify there're no crash dump files.
    622     for dmp_file in glob.glob(os.path.join(breakpad_folder, '*.dmp')):
    623       self.assertTrue(dmp_file in old_dmp_files,
    624                       msg='Crash dump %s found' % dmp_file)
    625 
    626     # Check for any crashed tabs.
    627     tabs = info['windows'][0]['tabs']
    628     for tab in tabs:
    629       if tab['url'] != 'about:blank':
    630         if not self.GetDOMValue('document.body.innerHTML', tab['index']):
    631           self.fail(msg='Tab crashed on %s' % tab['url'])
    632 
    633   def _GetPlatformArchitecture(self):
    634     """Get platform architecture.
    635 
    636     Returns:
    637       A string representing the platform architecture.
    638     """
    639     if pyauto.PyUITest.IsWin():
    640       if os.environ['PROGRAMFILES'] == 'C:\\Program Files (x86)':
    641         return '64bit'
    642       else:
    643         return '32bit'
    644     elif pyauto.PyUITest.IsMac() or pyauto.PyUITest.IsLinux():
    645       if platform.machine() == 'x86_64':
    646         return '64bit'
    647       else:
    648         return '32bit'
    649     return '32bit'
    650 
    651   def _HasPathInTree(self, pattern, is_file, root=os.curdir):
    652     """Recursively checks if a file/directory matching a pattern exists.
    653 
    654     Args:
    655       pattern: Pattern of file or directory name.
    656       is_file: True if looking for file, or False if looking for directory.
    657       root: Directory to start looking.
    658 
    659     Returns:
    660       True, if root contains the directory name pattern, or
    661       False otherwise.
    662     """
    663     for path, dirs, files in os.walk(os.path.abspath(root)):
    664       if is_file:
    665         if len(fnmatch.filter(files, pattern)):
    666           return True
    667       else:
    668         if len(fnmatch.filter(dirs, pattern)):
    669           return True
    670     return False
    671 
    672   def _HasAllSystemRequirements(self):
    673     """Verify NaCl SDK installation system requirements.
    674 
    675     Returns:
    676         True, if system passed requirements, or
    677         False otherwise.
    678     """
    679     # Check python version.
    680     if sys.version_info[0:2] < (2, 6):
    681       return False
    682 
    683     # Check OS requirements.
    684     if pyauto.PyUITest.IsMac():
    685       mac_min_version = version.StrictVersion('10.6')
    686       mac_version = version.StrictVersion(platform.mac_ver()[0])
    687       if mac_version < mac_min_version:
    688         return False
    689     elif pyauto.PyUITest.IsWin():
    690       if not (self.IsWin7() or self.IsWinVista() or self.IsWinXP()):
    691         return False
    692     elif pyauto.PyUITest.IsLinux():
    693       pass  # TODO(chrisphan): Check Lin requirements.
    694     else:
    695       return False
    696 
    697     # Check for Chrome version compatibility.
    698     # NaCl supports Chrome 10 and higher builds.
    699     min_required_chrome_build = self._settings['min_required_chrome_build']
    700     browser_info = self.GetBrowserInfo()
    701     chrome_version = browser_info['properties']['ChromeVersion']
    702     chrome_build = int(chrome_version.split('.')[0])
    703     return chrome_build >= min_required_chrome_build
    704 
    705   def _DownloadNaClSDK(self):
    706     """Download NaCl SDK."""
    707     self._temp_dir = tempfile.mkdtemp()
    708     dl_file = urllib2.urlopen(self._settings['post_sdk_zip'])
    709     file_path = os.path.join(self._temp_dir, 'nacl_sdk.zip')
    710 
    711     try:
    712       f = open(file_path, 'wb')
    713       f.write(dl_file.read())
    714     except IOError:
    715       self.fail(msg='Cannot open %s.' % file_path)
    716     finally:
    717       f.close()
    718 
    719   def _ExtractNaClSDK(self):
    720     """Extract NaCl SDK."""
    721     source_file = os.path.join(self._temp_dir, 'nacl_sdk.zip')
    722     if zipfile.is_zipfile(source_file):
    723       zip = zipfile.ZipFile(source_file, 'r')
    724       zip.extractall(self._extracted_sdk_path)
    725     else:
    726       self.fail(msg='%s is not a valid zip file' % source_file)
    727 
    728   def _IsURLAlive(self, url):
    729     """Test if URL is alive."""
    730     try:
    731       urllib2.urlopen(url)
    732     except:
    733       return False
    734     return True
    735 
    736   def _CloseHTTPServer(self, proc=None):
    737     """Close HTTP server.
    738 
    739     Args:
    740       proc: Process that opened the HTTP server.
    741       proc is None when there is no pointer to HTTP server process.
    742     """
    743     if not self._IsURLAlive('http://localhost:5103'):
    744       return
    745     response = urllib2.urlopen('http://localhost:5103')
    746     html = response.read()
    747     if not 'Native Client' in html:
    748       self.fail(msg='Port 5103 is in use.')
    749 
    750     urllib2.urlopen('http://localhost:5103?quit=1')
    751     success = self.WaitUntil(
    752         lambda: self._IsURLAlive('http://localhost:5103'),
    753         retry_sleep=1, expect_retval=False)
    754     if not success:
    755       if not proc:
    756         self.fail(msg='Failed to close HTTP server.')
    757       else:
    758         if proc.poll() == None:
    759           try:
    760             proc.kill()
    761           except:
    762             self.fail(msg='Failed to close HTTP server.')
    763 
    764   def _SearchNaClSDKFile(self, search_list):
    765     """Search NaCl SDK file for example files and directories in Windows.
    766 
    767     Args:
    768       search_list: A list of strings, representing file and
    769                    directory names for which to search.
    770     """
    771     missing_items = []
    772     for name in search_list:
    773       is_file = name.find('/') < 0
    774       if not is_file:
    775         name = name.replace('/', '')
    776       if not self._HasPathInTree(name, is_file, self._extracted_sdk_path):
    777         missing_items.append(name)
    778     self.assertEqual(len(missing_items), 0,
    779                      msg='Missing files or directories: %s' %
    780                          ', '.join(map(str, missing_items)))
    781 
    782   def ExtraChromeFlags(self):
    783     """Ensures Nacl is enabled.
    784 
    785     Returns:
    786       A list of extra flags to pass to Chrome when it is launched.
    787     """
    788     extra_chrome_flags = [
    789         '--enable-nacl',
    790         '--enable-nacl-exception-handling',
    791         '--nacl-gdb',
    792       ]
    793     return pyauto.PyUITest.ExtraChromeFlags(self) + extra_chrome_flags
    794 
    795 if __name__ == '__main__':
    796   pyauto_functional.Main()
    797