| OLD | NEW |
| 1 #!/usr/bin/python2.4 | 1 #!/usr/bin/python2.4 |
| 2 # Copyright 2009, Google Inc. | 2 # Copyright 2009, Google Inc. |
| 3 # All rights reserved. | 3 # All rights reserved. |
| 4 # | 4 # |
| 5 # Redistribution and use in source and binary forms, with or without | 5 # Redistribution and use in source and binary forms, with or without |
| 6 # modification, are permitted provided that the following conditions are | 6 # modification, are permitted provided that the following conditions are |
| 7 # met: | 7 # met: |
| 8 # | 8 # |
| 9 # * Redistributions of source code must retain the above copyright | 9 # * Redistributions of source code must retain the above copyright |
| 10 # notice, this list of conditions and the following disclaimer. | 10 # notice, this list of conditions and the following disclaimer. |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 54 import re | 54 import re |
| 55 import SimpleHTTPServer | 55 import SimpleHTTPServer |
| 56 import socket | 56 import socket |
| 57 import SocketServer | 57 import SocketServer |
| 58 import subprocess | 58 import subprocess |
| 59 import threading | 59 import threading |
| 60 import time | 60 import time |
| 61 import unittest | 61 import unittest |
| 62 import gflags | 62 import gflags |
| 63 import javascript_unit_tests | 63 import javascript_unit_tests |
| 64 # Import custom testrunner for pulse | 64 import test_runner |
| 65 import pulse_testrunner | |
| 66 import selenium | 65 import selenium |
| 67 import samples_tests | 66 import samples_tests |
| 68 import selenium_constants | 67 import selenium_constants |
| 69 import selenium_utilities | 68 import selenium_utilities |
| 69 import pdiff_test |
| 70 import Queue |
| 70 | 71 |
| 71 if sys.platform == 'win32' or sys.platform == 'cygwin': | 72 if sys.platform == 'win32' or sys.platform == 'cygwin': |
| 72 default_java_exe = "java.exe" | 73 default_java_exe = "java.exe" |
| 73 else: | 74 else: |
| 74 default_java_exe = "java" | 75 default_java_exe = "java" |
| 75 | 76 |
| 76 # Command line flags | 77 # Command line flags |
| 77 FLAGS = gflags.FLAGS | 78 FLAGS = gflags.FLAGS |
| 78 gflags.DEFINE_boolean("verbose", False, "verbosity") | 79 gflags.DEFINE_boolean("verbose", False, "verbosity") |
| 79 gflags.DEFINE_boolean("screenshots", False, "takes screenshots") | 80 gflags.DEFINE_boolean("screenshots", False, "takes screenshots") |
| (...skipping 27 matching lines...) Expand all Loading... |
| 107 "specifies the prefix of tests to run") | 108 "specifies the prefix of tests to run") |
| 108 gflags.DEFINE_string( | 109 gflags.DEFINE_string( |
| 109 "testsuffixes", | 110 "testsuffixes", |
| 110 "small,medium,large", | 111 "small,medium,large", |
| 111 "specifies the suffixes, separated by commas of tests to run") | 112 "specifies the suffixes, separated by commas of tests to run") |
| 112 gflags.DEFINE_string( | 113 gflags.DEFINE_string( |
| 113 "servertimeout", | 114 "servertimeout", |
| 114 "30", | 115 "30", |
| 115 "Specifies the timeout value, in seconds, for the selenium server.") | 116 "Specifies the timeout value, in seconds, for the selenium server.") |
| 116 | 117 |
| 118 |
| 117 # Browsers to choose from (for browser flag). | 119 # Browsers to choose from (for browser flag). |
| 118 # use --browser $BROWSER_NAME to run | 120 # use --browser $BROWSER_NAME to run |
| 119 # tests for that browser | 121 # tests for that browser |
| 120 gflags.DEFINE_list( | 122 gflags.DEFINE_list( |
| 121 "browser", | 123 "browser", |
| 122 "*firefox", | 124 "*firefox", |
| 123 "\n".join(["comma-separated list of browsers to test", | 125 "\n".join(["comma-separated list of browsers to test", |
| 124 "Options:"] + | 126 "Options:"] + |
| 125 selenium_constants.SELENIUM_BROWSER_SET)) | 127 selenium_constants.SELENIUM_BROWSER_SET)) |
| 126 gflags.DEFINE_string( | 128 gflags.DEFINE_string( |
| 127 "browserpath", | 129 "browserpath", |
| 128 "", | 130 "", |
| 129 "specifies the path to the browser executable " | 131 "specifies the path to the browser executable " |
| 130 "(for platforms that don't support MOZ_PLUGIN_PATH)") | 132 "(for platforms that don't support MOZ_PLUGIN_PATH)") |
| 131 gflags.DEFINE_string( | 133 gflags.DEFINE_string( |
| 132 "samplespath", | 134 "samplespath", |
| 133 "", | 135 "", |
| 134 "specifies the path from the web root to the samples.") | 136 "specifies the path from the web root to the samples.") |
| 135 | 137 |
| 136 | |
| 137 class MyRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): | 138 class MyRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): |
| 138 """Hook to handle HTTP server requests. | 139 """Hook to handle HTTP server requests. |
| 139 | 140 |
| 140 Functions as a handler for logging and other utility functions. | 141 Functions as a handler for logging and other utility functions. |
| 141 """ | 142 """ |
| 142 | 143 |
| 143 def log_message(self, format, *args): | 144 def log_message(self, format, *args): |
| 144 """Logging hook for HTTP server.""" | 145 """Logging hook for HTTP server.""" |
| 145 | 146 |
| 146 # For now, just suppress logging. | 147 # For now, just suppress logging. |
| 147 pass | 148 pass |
| 148 # TODO: might be nice to have a verbose option for debugging. | 149 # TODO: might be nice to have a verbose option for debugging. |
| 149 | 150 |
| 151 |
| 152 |
| 150 | 153 |
| 151 class LocalFileHTTPServer(threading.Thread): | 154 class LocalFileHTTPServer(threading.Thread): |
| 152 """Minimal HTTP server that serves local files. | 155 """Minimal HTTP server that serves local files. |
| 153 | 156 |
| 154 Members: | 157 Members: |
| 155 http_alive: event to signal that http server is up and running | 158 http_alive: event to signal that http server is up and running |
| 156 http_port: the TCP port the server is using | 159 http_port: the TCP port the server is using |
| 157 """ | 160 """ |
| 158 | 161 |
| 159 START_PORT = 8100 | 162 START_PORT = 8100 |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 if not selenium_server.selenium_port: | 344 if not selenium_server.selenium_port: |
| 342 print 'Timed out.' | 345 print 'Timed out.' |
| 343 return None | 346 return None |
| 344 | 347 |
| 345 print("Selenium RC server started on port %d" | 348 print("Selenium RC server started on port %d" |
| 346 % selenium_server.selenium_port) | 349 % selenium_server.selenium_port) |
| 347 | 350 |
| 348 return selenium_server | 351 return selenium_server |
| 349 | 352 |
| 350 | 353 |
| 351 class SeleniumSession(object): | 354 class SeleniumSessionBuilder: |
| 352 """A selenium browser session, with support servers. | 355 def __init__(self, sel_port, sel_timeout, http_port, browserpath): |
| 353 | 356 |
| 354 The support servers include a Selenium Remote Control server, and | 357 self.sel_port = sel_port |
| 355 a local HTTP server to serve static test files. | 358 self.sel_timeout = sel_timeout |
| 359 self.http_port = http_port |
| 360 self.browserpath = browserpath |
| 356 | 361 |
| 357 Members: | 362 def NewSeleniumSession(self, browser): |
| 358 session: a selenium() instance | |
| 359 selenium_server: a SeleniumRemoteControl() instance | |
| 360 http_server: a LocalFileHTTPServer() instance | |
| 361 runner: a TestRunner() instance | |
| 362 """ | |
| 363 | |
| 364 def __init__(self, verbose, java_path, selenium_server, server_timeout, | |
| 365 http_root=None): | |
| 366 """Initializes a Selenium Session. | |
| 367 | |
| 368 Args: | |
| 369 verbose: boolean verbose flag | |
| 370 java_path: path to java used to run selenium. | |
| 371 selenium_server: path to jar containing selenium server. | |
| 372 server_timeout: server timeout value, in seconds. | |
| 373 http_root: Serve http pages using this path as the document root. When | |
| 374 None, use the default. | |
| 375 """ | |
| 376 # Start up a static file server, to serve the test pages. | |
| 377 | |
| 378 if not http_root: | |
| 379 http_root = FLAGS.product_dir | |
| 380 | |
| 381 self.http_server = LocalFileHTTPServer.StartServer(http_root) | |
| 382 | |
| 383 if self.http_server: | |
| 384 # Start up the Selenium Remote Control Server | |
| 385 self.selenium_server = SeleniumRemoteControl.StartServer(verbose, | |
| 386 java_path, | |
| 387 selenium_server, | |
| 388 server_timeout) | |
| 389 if not self.http_server or not self.selenium_server: | |
| 390 return | |
| 391 | |
| 392 # Set up a testing runner | |
| 393 self.runner = pulse_testrunner.PulseTestRunner() | |
| 394 | |
| 395 # Set up a phantom selenium session so we can call shutdown if needed. | |
| 396 self.session = selenium.selenium( | |
| 397 "localhost", self.selenium_server.selenium_port, "*firefox", | |
| 398 "http://" + socket.gethostname() + ":" + | |
| 399 str(self.http_server.http_port)) | |
| 400 | |
| 401 def StartSession(self, browser): | |
| 402 """Starts the Selenium Session and connects to the HTTP server. | |
| 403 | |
| 404 Args: | |
| 405 browser: selenium browser name | |
| 406 """ | |
| 407 | |
| 408 if browser == "*googlechrome": | 363 if browser == "*googlechrome": |
| 409 # TODO: Replace socket.gethostname() with "localhost" | 364 # TODO: Replace socket.gethostname() with "localhost" |
| 410 # once Chrome local proxy fix is in. | 365 # once Chrome local proxy fix is in. |
| 411 server_url = "http://" + socket.gethostname() + ":" | 366 server_url = "http://" + socket.gethostname() + ":" |
| 412 else: | 367 else: |
| 413 server_url = "http://localhost:" | 368 server_url = "http://localhost:" |
| 414 server_url += str(self.http_server.http_port) | 369 server_url += str(self.http_port) |
| 415 | 370 |
| 416 browser_path_with_space = "" | 371 browser_path_with_space = "" |
| 417 if FLAGS.browserpath: | 372 if self.browserpath: |
| 418 browser_path_with_space = " " + FLAGS.browserpath | 373 browser_path_with_space = " " + self.browserpath |
| 419 | |
| 420 self.session = selenium.selenium("localhost", | |
| 421 self.selenium_server.selenium_port, | |
| 422 browser + browser_path_with_space, | |
| 423 server_url) | |
| 424 self.session.start() | |
| 425 | |
| 426 def CloseSession(self): | |
| 427 """Closes the selenium sesssion.""" | |
| 428 self.session.stop() | |
| 429 | |
| 430 def TearDown(self): | |
| 431 """Stops the selenium server.""" | |
| 432 self.session.shut_down_selenium_server() | |
| 433 | |
| 434 def TestBrowser(self, browser, test_list, test_prefix, test_suffixes, | |
| 435 server_timeout): | |
| 436 """Runs Selenium tests for a specific browser. | |
| 437 | |
| 438 Args: | |
| 439 browser: selenium browser name (eg. *iexplore, *firefox). | |
| 440 test_list: list to add tests to. | |
| 441 test_prefix: prefix of tests to run. | |
| 442 test_suffixes: comma separated suffixes of tests to run. | |
| 443 server_timeout: server timeout value, in milliseconds | |
| 444 | |
| 445 Returns: | |
| 446 result: result of test runner. | |
| 447 """ | |
| 448 print "Testing %s..." % browser | |
| 449 self.StartSession(browser) | |
| 450 self.session.set_timeout(server_timeout) | |
| 451 self.runner.setBrowser(browser) | |
| 452 | |
| 453 try: | |
| 454 result = self.runner.run( | |
| 455 SeleniumSuite(self.session, browser, test_list, | |
| 456 test_prefix, test_suffixes)) | |
| 457 finally: | |
| 458 self.CloseSession() | |
| 459 | |
| 460 return result | |
| 461 | 374 |
| 462 | 375 |
| 463 class LocalTestSuite(unittest.TestSuite): | 376 new_session = selenium.selenium("localhost", |
| 464 """Wrapper for unittest.TestSuite so we can collect the tests.""" | 377 self.sel_port, |
| 378 browser + browser_path_with_space, |
| 379 server_url) |
| 380 |
| 381 new_session.start() |
| 382 new_session.set_timeout(self.sel_timeout) |
| 383 |
| 384 return new_session |
| 465 | 385 |
| 466 def __init__(self): | |
| 467 unittest.TestSuite.__init__(self) | |
| 468 self.test_list = [] | |
| 469 | 386 |
| 470 def addTest(self, name, test): | 387 def TestBrowser(session_builder, browser, test_list): |
| 471 """Adds a test to the TestSuite and records its name and test_path. | 388 """Runs Selenium tests for a specific browser. |
| 472 | 389 |
| 473 Args: | 390 Args: |
| 474 name: name of test. | 391 session_builder: session_builder for creating new selenium sessions. |
| 475 test: test to pass to unittest.TestSuite. | 392 browser: selenium browser name (eg. *iexplore, *firefox). |
| 476 """ | 393 test_list: list of tests. |
| 477 unittest.TestSuite.addTest(self, test) | 394 |
| 478 try: | 395 Returns: |
| 479 self.test_list.append((name, test.options)) | 396 summary_result: result of test runners. |
| 480 except AttributeError: | 397 """ |
| 481 self.test_list.append((name, [])) | 398 print "Testing %s..." % browser |
| 399 |
| 400 summary_result = test_runner.TestResult(test_runner.StringBuffer(), browser) |
| 401 |
| 402 # Fill up the selenium test queue. |
| 403 test_queue = Queue.Queue() |
| 404 for test in test_list: |
| 405 test_queue.put(test) |
| 406 |
| 407 |
| 408 pdiff_queue = None |
| 409 if FLAGS.screenshots: |
| 410 # Need to do screen comparisons. |
| 411 # |pdiff_queue| is the queue of perceptual diff tests that need to be done. |
| 412 # This queue is added to by individual slenium test runners. |
| 413 # |pdiff_result_queue| is the result of the perceptual diff tests. |
| 414 pdiff_queue = Queue.Queue() |
| 415 pdiff_result_queue = Queue.Queue() |
| 416 pdiff_worker = test_runner.PDiffTestRunner(pdiff_queue, |
| 417 pdiff_result_queue, |
| 418 browser) |
| 419 pdiff_worker.start() |
| 420 |
| 421 # Start initial selenium test runner. |
| 422 worker = test_runner.SeleniumTestRunner(session_builder, browser, |
| 423 test_queue, pdiff_queue) |
| 424 worker.start() |
| 425 |
| 426 # Run through all selenium tests. |
| 427 while not worker.IsCompletelyDone(): |
| 428 if worker.IsTesting() and worker.IsPastDeadline(): |
| 429 # Test has taken more than allotted. Abort and go to next test. |
| 430 worker.AbortTest() |
| 431 |
| 432 elif worker.DidFinishTest(): |
| 433 # Do this so that a worker does not grab test off queue till we tell it.
|
| 434 result = worker.Continue() |
| 435 result.printAll(sys.stdout) |
| 436 summary_result.merge(result) |
| 437 |
| 438 if FLAGS.screenshots: |
| 439 # Finish screenshot comparisons. |
| 440 pdiff_worker.EndTesting() |
| 441 while not pdiff_worker.IsCompletelyDone(): |
| 442 time.sleep(1) |
| 443 |
| 444 # Be careful here, make sure no one else is editing |pdiff_reult_queue|. |
| 445 while not pdiff_result_queue.empty(): |
| 446 result = pdiff_result_queue.get() |
| 447 result.printAll(sys.stdout) |
| 448 summary_result.merge(result) |
| 449 |
| 450 return summary_result |
| 451 |
| 482 | 452 |
| 483 | 453 |
| 484 def MatchesSuffix(name, suffixes): | 454 def MatchesSuffix(name, suffixes): |
| 485 """Checks if a name ends in one of the suffixes. | 455 """Checks if a name ends in one of the suffixes. |
| 486 | 456 |
| 487 Args: | 457 Args: |
| 488 name: Name to test. | 458 name: Name to test. |
| 489 suffixes: list of suffixes to test for. | 459 suffixes: list of suffixes to test for. |
| 490 Returns: | 460 Returns: |
| 491 True if name ends in one of the suffixes or if suffixes is empty. | 461 True if name ends in one of the suffixes or if suffixes is empty. |
| 492 """ | 462 """ |
| 493 if suffixes: | 463 if suffixes: |
| 494 name_lower = name.lower() | 464 name_lower = name.lower() |
| 495 for suffix in suffixes: | 465 for suffix in suffixes: |
| 496 if name_lower.endswith(suffix): | 466 if name_lower.endswith(suffix): |
| 497 return True | 467 return True |
| 498 return False | 468 return False |
| 499 else: | 469 else: |
| 500 return True | 470 return True |
| 501 | 471 |
| 502 | 472 |
| 503 def AddTests(test_suite, session, browser, module, filename, prefix, | 473 def _GetTestsFromFile(filename, prefix, test_prefix_filter, test_suffixes, |
| 504 test_prefix_filter, test_suffixes, path_to_html): | 474 browser, module, path_to_html): |
| 505 """Add tests defined in filename. | 475 """Add tests defined in filename, and associated perceptual diff test, if |
| 476 needed. |
| 506 | 477 |
| 507 Assumes module has a method "GenericTest" that uses self.args to run. | 478 Assumes module has a method "GenericTest" that uses self.args to run. |
| 508 | 479 |
| 509 Args: | 480 Args: |
| 510 test_suite: A Selenium test_suite to add tests to. | |
| 511 session: a Selenium instance. | |
| 512 browser: browser name. | |
| 513 module: module which will have method GenericTest() called to run each test. | |
| 514 filename: filename of file with list of tests. | 481 filename: filename of file with list of tests. |
| 515 prefix: prefix to add to the beginning of each test. | 482 prefix: prefix to add to the beginning of each test. |
| 516 test_prefix_filter: Only adds a test if it starts with this. | 483 test_prefix_filter: Only adds a test if it starts with this. |
| 517 test_suffixes: list of suffixes to filter by. An empty list = pass all. | 484 test_suffixes: list of suffixes to filter by. An empty list = pass all. |
| 485 browser: browser name. |
| 486 module: module which will have method GenericTest() called to run each test.
|
| 518 path_to_html: Path from server root to html | 487 path_to_html: Path from server root to html |
| 519 """ | 488 """ |
| 520 # See comments in that file for the expected format. | 489 # See comments in that file for the expected format. |
| 521 # skip lines that are blank or have "#" or ";" as their first non whitespace | 490 # skip lines that are blank or have "#" or ";" as their first non whitespace |
| 522 # character. | 491 # character. |
| 523 test_list_file = open(filename, "r") | 492 test_list_file = open(filename, "r") |
| 524 samples = test_list_file.readlines() | 493 samples = test_list_file.readlines() |
| 525 test_list_file.close() | 494 test_list_file.close() |
| 526 | 495 |
| 496 tests = [] |
| 497 |
| 527 for sample in samples: | 498 for sample in samples: |
| 528 sample = sample.strip() | 499 sample = sample.strip() |
| 529 if not sample or sample[0] == ";" or sample[0] == "#": | 500 if not sample or sample[0] == ";" or sample[0] == "#": |
| 530 continue | 501 continue |
| 531 | 502 |
| 532 arguments = sample.split() | 503 arguments = sample.split() |
| 533 test_type = arguments[0].lower() | 504 test_type = arguments[0].lower() |
| 534 test_path = arguments[1] | 505 test_path = arguments[1] |
| 535 options = arguments[2:] | 506 options = arguments[2:] |
| 536 | 507 |
| 537 # TODO: Add filter based on test_type | 508 # TODO: Add filter based on test_type |
| 538 | 509 if test_path.startswith("Test"): |
| 539 name = ("Test" + prefix + re.sub("\W", "_", test_path) + | 510 name = test_path |
| 540 test_type.capitalize()) | 511 else: |
| 512 # Need to make a name. |
| 513 name = ("Test" + prefix + re.sub("\W", "_", test_path) + |
| 514 test_type.capitalize()) |
| 541 | 515 |
| 542 # Only execute this test if the current browser is not in the list | 516 # Only execute this test if the current browser is not in the list |
| 543 # of skipped browsers. | 517 # of skipped browsers. |
| 544 test_skipped = False | 518 test_skipped = False |
| 519 screenshot_count = 0 |
| 545 for option in options: | 520 for option in options: |
| 546 if option.startswith("except"): | 521 if option.startswith("except"): |
| 547 skipped_platforms = selenium_utilities.GetArgument(option) | 522 skipped_platforms = selenium_utilities.GetArgument(option) |
| 548 if not skipped_platforms is None: | 523 if not skipped_platforms is None: |
| 549 skipped_platforms = skipped_platforms.split(",") | 524 skipped_platforms = skipped_platforms.split(",") |
| 550 if browser in skipped_platforms: | 525 if browser in skipped_platforms: |
| 551 test_skipped = True | 526 test_skipped = True |
| 527 elif option.startswith("screenshots"): |
| 528 screenshot_count += int(selenium_utilities.GetArgument(option)) |
| 529 elif option.startswith("screenshot"): |
| 530 screenshot_count += 1 |
| 531 |
| 532 if (test_prefix_filter and not name.startswith(test_prefix_filter) or |
| 533 test_suffixes and not MatchesSuffix(name, test_suffixes)): |
| 534 test_skipped = True |
| 552 | 535 |
| 553 if not test_skipped: | 536 if not test_skipped: |
| 554 # Check if there is already a test function by this name in the module. | 537 # Add a test method with this name if it doesn't exist. |
| 555 if (test_path.startswith(test_prefix_filter) and | 538 if not (hasattr(module, name) and callable(getattr(module, name))): |
| 556 hasattr(module, test_path) and callable(getattr(module, test_path))): | |
| 557 test_suite.addTest(test_path, module(test_path, session, browser, | |
| 558 path_to_html, options=options)) | |
| 559 elif (name.startswith(test_prefix_filter) and | |
| 560 MatchesSuffix(name, test_suffixes)): | |
| 561 # no, so add a method that will run a test generically. | |
| 562 setattr(module, name, module.GenericTest) | 539 setattr(module, name, module.GenericTest) |
| 563 test_suite.addTest(name, module(name, session, browser, path_to_html, | 540 |
| 564 test_type, test_path, options)) | 541 new_test = module(name, browser, path_to_html, test_type, test_path, |
| 542 options) |
| 543 |
| 544 if screenshot_count and FLAGS.screenshots: |
| 545 pdiff_name = name + 'Screenshots' |
| 546 screenshot = selenium_utilities.ScreenshotNameFromTestName(test_path) |
| 547 setattr(pdiff_test.PDiffTest, pdiff_name, |
| 548 pdiff_test.PDiffTest.PDiffTest) |
| 549 new_pdiff = pdiff_test.PDiffTest(pdiff_name, |
| 550 screenshot_count, |
| 551 screenshot, |
| 552 FLAGS.screencompare, |
| 553 FLAGS.screenshotsdir, |
| 554 FLAGS.referencedir, |
| 555 options) |
| 556 tests += [(new_test, new_pdiff)] |
| 557 else: |
| 558 tests += [new_test] |
| 559 |
| 560 |
| 561 return tests |
| 565 | 562 |
| 566 | 563 |
| 567 def SeleniumSuite(session, browser, test_list, test_prefix, test_suffixes): | 564 def GetTestsForBrowser(browser, test_prefix, test_suffixes): |
| 568 """Creates a test suite to run the unit tests. | 565 """Returns list of tests from test files. |
| 569 | 566 |
| 570 Args: | 567 Args: |
| 571 session: a selenium() instance | |
| 572 browser: browser name | 568 browser: browser name |
| 573 test_list: list to add tests to. | |
| 574 test_prefix: prefix of tests to run. | 569 test_prefix: prefix of tests to run. |
| 575 test_suffixes: A comma separated string of suffixes to filter by. | 570 test_suffixes: A comma separated string of suffixes to filter by. |
| 576 Returns: | 571 Returns: |
| 577 A selenium test suite. | 572 A list of unittest.TestCase. |
| 578 """ | 573 """ |
| 579 | 574 tests = [] |
| 580 test_suite = LocalTestSuite() | |
| 581 | |
| 582 suffixes = test_suffixes.split(",") | 575 suffixes = test_suffixes.split(",") |
| 583 | 576 |
| 584 # add sample tests. | 577 # add sample tests. |
| 585 filename = os.path.abspath(os.path.join(script_dir, "sample_list.txt")) | 578 filename = os.path.abspath(os.path.join(script_dir, "sample_list.txt")) |
| 586 AddTests(test_suite, | 579 tests += _GetTestsFromFile(filename, "Sample", test_prefix, suffixes, browser, |
| 587 session, | 580 samples_tests.SampleTests, |
| 588 browser, | 581 FLAGS.samplespath.replace("\\","/")) |
| 589 samples_tests.SampleTests, | 582 |
| 590 filename, | |
| 591 "Sample", | |
| 592 test_prefix, | |
| 593 suffixes, | |
| 594 FLAGS.samplespath.replace("\\", "/")) | |
| 595 | |
| 596 # add javascript tests. | 583 # add javascript tests. |
| 597 filename = os.path.abspath(os.path.join(script_dir, | 584 filename = os.path.abspath(os.path.join(script_dir, |
| 598 "javascript_unit_test_list.txt")) | 585 "javascript_unit_test_list.txt")) |
| 599 AddTests(test_suite, | 586 tests += _GetTestsFromFile(filename, "UnitTest", test_prefix, suffixes, |
| 600 session, | 587 browser, javascript_unit_tests.JavaScriptUnitTests, |
| 601 browser, | 588 "") |
| 602 javascript_unit_tests.JavaScriptUnitTests, | |
| 603 filename, | |
| 604 "UnitTest", | |
| 605 test_prefix, | |
| 606 suffixes, | |
| 607 '') | |
| 608 | 589 |
| 609 test_list += test_suite.test_list | 590 return tests |
| 610 | |
| 611 return test_suite | |
| 612 | 591 |
| 613 | 592 |
| 614 def CompareScreenshots(browser, test_list, screencompare, screenshotsdir, | 593 def GetChromePath(): |
| 615 screencompare_tool, verbose): | 594 value = None |
| 616 """Performs the image validation for test-case frame captures. | 595 if sys.platform == "win32" or sys.platform == "cygwin": |
| 617 | 596 import _winreg |
| 618 Args: | 597 try: |
| 619 browser: selenium browser name | 598 key = _winreg.OpenKey(_winreg.HKEY_CLASSES_ROOT, |
| 620 test_list: list of tests that ran. | 599 "Applications\\chrome.exe\\shell\\open\\command") |
| 621 screencompare: True to actually run tests. | 600 (value, type) = _winreg.QueryValueEx(key, None) |
| 622 screenshotsdir: path of directory containing images to compare. | 601 _winreg.CloseKey(key) |
| 623 screencompare_tool: path to image diff tool. | 602 value = os.path.dirname(value) |
| 624 verbose: If True then outputs verbose info. | 603 |
| 625 | 604 except WindowsError: |
| 626 Returns: | 605 value = None |
| 627 A Results object. | 606 if '*googlechrome' in FLAGS.browser: |
| 628 """ | 607 raise Exception("Unable to determine location for Chrome -- " + |
| 629 print "Validating captured frames against reference data..." | 608 "is it installed?") |
| 630 | 609 |
| 631 class Results(object): | 610 return value |
| 632 """An object to return results of screenshot compares. | |
| 633 | |
| 634 Similar to unittest.TestResults. | |
| 635 """ | |
| 636 | |
| 637 def __init__(self): | |
| 638 object.__init__(self) | |
| 639 self.tests_run = 0 | |
| 640 self.current_test = None | |
| 641 self.errors = [] | |
| 642 self.failures = [] | |
| 643 self.start_time = 0 | |
| 644 | |
| 645 def StartTest(self, test): | |
| 646 """Adds a test. | |
| 647 | |
| 648 Args: | |
| 649 test: name of test. | |
| 650 """ | |
| 651 self.start_time = time.time() | |
| 652 self.tests_run += 1 | |
| 653 self.current_test = test | |
| 654 | |
| 655 def TimeTaken(self): | |
| 656 """Returns the time since the last call to StartTest.""" | |
| 657 return time.time() - self.start_time | |
| 658 | |
| 659 def AddFailure(self, test, browser, message): | |
| 660 """Adds a failure. | |
| 661 | |
| 662 Args: | |
| 663 test: name of the test. | |
| 664 browser: name of the browser. | |
| 665 message: error message to print | |
| 666 """ | |
| 667 self.failures.append(test) | |
| 668 print "ERROR: ", message | |
| 669 print("SELENIUMRESULT %s <%s> [%.3fs]: FAIL" | |
| 670 % (test, browser, self.TimeTaken())) | |
| 671 | |
| 672 def AddSuccess(self, test): | |
| 673 """Adds a success. | |
| 674 | |
| 675 Args: | |
| 676 test: name of the test. | |
| 677 """ | |
| 678 print("SELENIUMRESULT %s <%s> [%.3fs]: PASS" | |
| 679 % (test, browser, self.TimeTaken())) | |
| 680 | |
| 681 def WasSuccessful(self): | |
| 682 """Returns true if all tests were successful.""" | |
| 683 return not self.errors and not self.failures | |
| 684 | |
| 685 results = Results() | |
| 686 | |
| 687 if not screencompare: | |
| 688 return results | |
| 689 | |
| 690 base_path = os.getcwd() | |
| 691 | |
| 692 reference_files = os.listdir(os.path.join( | |
| 693 base_path, | |
| 694 selenium_constants.REFERENCE_SCREENSHOT_PATH)) | |
| 695 | |
| 696 generated_files = os.listdir(os.path.join(base_path, screenshotsdir)) | |
| 697 | |
| 698 # Prep the test list for matching | |
| 699 temp = [] | |
| 700 for (test, options) in test_list: | |
| 701 test = selenium_utilities.StripTestTypeSuffix(test) | |
| 702 temp.append((test.lower(), options)) | |
| 703 test_list = temp | |
| 704 | |
| 705 # Create regex object for filename | |
| 706 # file is in format "FILENAME_reference.png" | |
| 707 reference_file_name_regex = re.compile(r"^(.*)_reference\.png") | |
| 708 generated_file_name_regex = re.compile(r"^(.*)\.png") | |
| 709 | |
| 710 # check that there is a reference file for each generated file. | |
| 711 for file_name in generated_files: | |
| 712 match = generated_file_name_regex.search(file_name) | |
| 713 | |
| 714 if match is None: | |
| 715 # no matches | |
| 716 continue | |
| 717 | |
| 718 # Generated file name without png extension | |
| 719 actual_name = match.group(1) | |
| 720 | |
| 721 # Get full paths to reference and generated files | |
| 722 reference_file = os.path.join( | |
| 723 base_path, | |
| 724 selenium_constants.REFERENCE_SCREENSHOT_PATH, | |
| 725 actual_name + "_reference.png") | |
| 726 generated_file = os.path.join( | |
| 727 base_path, | |
| 728 screenshotsdir, | |
| 729 actual_name + ".png") | |
| 730 | |
| 731 test_name = "TestReferenceScreenshotExists_" + actual_name | |
| 732 results.StartTest(test_name) | |
| 733 if not os.path.exists(reference_file): | |
| 734 # reference file does not exist | |
| 735 results.AddFailure( | |
| 736 test_name, browser, | |
| 737 "Missing reference file %s for generated file %s." % | |
| 738 (reference_file, generated_file)) | |
| 739 else: | |
| 740 results.AddSuccess(test_name) | |
| 741 | |
| 742 # Assuming both the result and reference image sets are the same size, | |
| 743 # verify that corresponding images are similar within tolerance. | |
| 744 for file_name in reference_files: | |
| 745 match = reference_file_name_regex.search(file_name) | |
| 746 | |
| 747 if match is None: | |
| 748 # no matches | |
| 749 continue | |
| 750 | |
| 751 # Generated file name without png extension | |
| 752 actual_name = match.group(1) | |
| 753 # Get full paths to reference and generated files | |
| 754 reference_file = os.path.join( | |
| 755 base_path, | |
| 756 selenium_constants.REFERENCE_SCREENSHOT_PATH, | |
| 757 file_name) | |
| 758 platform_specific_reference_file = os.path.join( | |
| 759 base_path, | |
| 760 selenium_constants.PLATFORM_SPECIFIC_REFERENCE_SCREENSHOT_PATH, | |
| 761 actual_name + "_reference.png") | |
| 762 generated_file = os.path.join( | |
| 763 base_path, | |
| 764 screenshotsdir, | |
| 765 actual_name + ".png") | |
| 766 | |
| 767 # Generate a test case name | |
| 768 test_name = "TestScreenCompare_" + actual_name | |
| 769 | |
| 770 # skip the reference file if the test is not in the test list. | |
| 771 basename = os.path.splitext(os.path.basename(file_name))[0] | |
| 772 basename = re.sub("\d+_reference", "", basename).lower() | |
| 773 basename = re.sub("\W", "_", basename) | |
| 774 test_was_run = False | |
| 775 test_options = [] | |
| 776 for (test, options) in test_list: | |
| 777 if test.endswith(basename): | |
| 778 test_was_run = True | |
| 779 test_options = options or [] | |
| 780 break | |
| 781 | |
| 782 if test_was_run: | |
| 783 results.StartTest(test_name) | |
| 784 else: | |
| 785 # test was not planned to run for this reference image. | |
| 786 if os.path.exists(generated_file): | |
| 787 # a generated file exists? The test name does not match the screenshot. | |
| 788 results.StartTest(test_name) | |
| 789 results.AddFailure(test_name, browser, | |
| 790 "Test name and screenshot name do not match.") | |
| 791 continue | |
| 792 | |
| 793 # Check if there is a platform specific version of the reference image | |
| 794 if os.path.exists(platform_specific_reference_file): | |
| 795 reference_file = platform_specific_reference_file | |
| 796 | |
| 797 # Check if perceptual diff exists | |
| 798 pdiff_path = os.path.join(base_path, screencompare_tool) | |
| 799 if not os.path.exists(pdiff_path): | |
| 800 # Perceptualdiff.exe does not exist, fail. | |
| 801 results.AddFailure( | |
| 802 test_name, browser, | |
| 803 "Perceptual diff %s does not exist." % pdiff_path) | |
| 804 continue | |
| 805 | |
| 806 pixel_threshold = "10" | |
| 807 alpha_threshold = "1.0" | |
| 808 use_colorfactor = False | |
| 809 use_downsample = False | |
| 810 use_edge = True | |
| 811 edge_threshold = "5" | |
| 812 | |
| 813 # Find out if the test specified any options relating to perceptual diff | |
| 814 # that will override the defaults. | |
| 815 for opt in test_options: | |
| 816 if opt.startswith("pdiff_threshold"): | |
| 817 pixel_threshold = selenium_utilities.GetArgument(opt) | |
| 818 elif (opt.startswith("pdiff_threshold_mac") and | |
| 819 sys.platform == "darwin"): | |
| 820 pixel_threshold = selenium_utilities.GetArgument(opt) | |
| 821 elif (opt.startswith("pdiff_threshold_win") and | |
| 822 sys.platform == 'win32' or sys.platform == "cygwin"): | |
| 823 pixel_threshold = selenium_utilities.GetArgument(opt) | |
| 824 elif (opt.startswith("pdiff_threshold_linux") and | |
| 825 sys.platform[:5] == "linux"): | |
| 826 pixel_threshold = selenium_utilities.GetArgument(opt) | |
| 827 elif (opt.startswith("colorfactor")): | |
| 828 colorfactor = selenium_utilities.GetArgument(opt) | |
| 829 use_colorfactor = True | |
| 830 elif (opt.startswith("downsample")): | |
| 831 downsample_factor = selenium_utilities.GetArgument(opt) | |
| 832 use_downsample = True | |
| 833 elif (opt.startswith("pdiff_edge_ignore_off")): | |
| 834 use_edge = False | |
| 835 elif (opt.startswith("pdiff_edge_threshold")): | |
| 836 edge_threshold = selenium_utilities.GetArgument(opt) | |
| 837 | |
| 838 # Check if file exists | |
| 839 if os.path.exists(generated_file): | |
| 840 diff_file = os.path.join(base_path, screenshotsdir, | |
| 841 "compare_%s.png" % actual_name) | |
| 842 | |
| 843 # Run perceptual diff | |
| 844 arguments = [pdiff_path, | |
| 845 reference_file, | |
| 846 generated_file, | |
| 847 "-output", diff_file, | |
| 848 "-fov", "45", | |
| 849 "-alphaThreshold", alpha_threshold, | |
| 850 # Turn on verbose output for the percetual diff so we | |
| 851 # can see how far off we are on the threshold. | |
| 852 "-verbose", | |
| 853 # Set the threshold to zero so we can get a count | |
| 854 # of the different pixels. This causes the program | |
| 855 # to return failure for most images, but we can compare | |
| 856 # the values ourselves below. | |
| 857 "-threshold", "0"] | |
| 858 if use_colorfactor: | |
| 859 arguments += ["-colorfactor", colorfactor] | |
| 860 if use_downsample: | |
| 861 arguments += ["-downsample", downsample_factor] | |
| 862 if use_edge: | |
| 863 arguments += ["-ignoreEdges", edge_threshold] | |
| 864 | |
| 865 # Print the perceptual diff command line so we can debug easier. | |
| 866 if verbose: | |
| 867 print " ".join(arguments) | |
| 868 | |
| 869 # diff tool should return 0 on success | |
| 870 expected_result = 0 | |
| 871 | |
| 872 pdiff_pipe = subprocess.Popen(arguments, | |
| 873 stdout=subprocess.PIPE, | |
| 874 stderr=subprocess.PIPE) | |
| 875 (pdiff_stdout, pdiff_stderr) = pdiff_pipe.communicate() | |
| 876 result = pdiff_pipe.returncode | |
| 877 | |
| 878 # Find out how many pixels were different by looking at the output. | |
| 879 pixel_re = re.compile("(\d+) pixels are different", re.DOTALL) | |
| 880 pixel_match = pixel_re.search(pdiff_stdout) | |
| 881 different_pixels = "0" | |
| 882 if pixel_match: | |
| 883 different_pixels = pixel_match.group(1) | |
| 884 | |
| 885 alpha_re = re.compile("max alpha delta of ([0-9\.]+)", re.DOTALL) | |
| 886 alpha_delta = "0.0" | |
| 887 alpha_match = alpha_re.search(pdiff_stdout) | |
| 888 if alpha_match: | |
| 889 alpha_delta = alpha_match.group(1) | |
| 890 | |
| 891 if (result == expected_result or (pixel_match and | |
| 892 int(different_pixels) <= int(pixel_threshold))): | |
| 893 # The perceptual diff passed. | |
| 894 pass_re = re.compile("PASS: (.*?)\n", re.DOTALL) | |
| 895 pass_match = pass_re.search(pdiff_stdout) | |
| 896 reason = "Images are not perceptually different." | |
| 897 if pass_match: | |
| 898 reason = pass_match.group(1) | |
| 899 print ("%s PASSED with %s different pixels " | |
| 900 "(threshold %s) because: %s" % (test_name, | |
| 901 different_pixels, | |
| 902 pixel_threshold, | |
| 903 reason)) | |
| 904 results.AddSuccess(test_name) | |
| 905 else: | |
| 906 # The perceptual diff failed. | |
| 907 if pixel_match and int(different_pixels) > int(pixel_threshold): | |
| 908 results.AddFailure( | |
| 909 test_name, browser, | |
| 910 ("Reference framebuffer (%s) does not match generated " | |
| 911 "file (%s): %s non-matching pixels, max alpha delta: %s, " | |
| 912 "threshold: %s, alphaThreshold: %s." % | |
| 913 (reference_file, generated_file, different_pixels, alpha_delta, | |
| 914 pixel_threshold, alpha_threshold))) | |
| 915 else: | |
| 916 # The perceptual diff failed for some reason other than | |
| 917 # pixel differencing. | |
| 918 fail_re = re.compile("FAIL: (.*?)\n", re.DOTALL) | |
| 919 fail_match = fail_re.search(pdiff_stdout) | |
| 920 reason = "Unknown failure" | |
| 921 if fail_match: | |
| 922 reason = fail_match.group(1) | |
| 923 results.AddFailure( | |
| 924 test_name, browser, | |
| 925 ("Perceptual diff of reference (%s) and generated (%s) files " | |
| 926 "failed because: %s" % | |
| 927 (reference_file, generated_file, reason))) | |
| 928 else: | |
| 929 # Generated file does not exist | |
| 930 results.AddFailure(test_name, browser, | |
| 931 "File %s does not exist." % generated_file) | |
| 932 | |
| 933 return results | |
| 934 | 611 |
| 935 | 612 |
| 936 def main(unused_argv): | 613 def main(unused_argv): |
| 937 # Boolean to record if all tests passed. | 614 # Boolean to record if all tests passed. |
| 938 all_tests_passed = True | 615 all_tests_passed = True |
| 939 | 616 |
| 940 selenium_constants.REFERENCE_SCREENSHOT_PATH = os.path.join( | 617 selenium_constants.REFERENCE_SCREENSHOT_PATH = os.path.join( |
| 941 FLAGS.referencedir, | 618 FLAGS.referencedir, |
| 942 "reference", | 619 "reference", |
| 943 "") | 620 "") |
| 944 selenium_constants.PLATFORM_SPECIFIC_REFERENCE_SCREENSHOT_PATH = os.path.join( | 621 selenium_constants.PLATFORM_SPECIFIC_REFERENCE_SCREENSHOT_PATH = os.path.join( |
| 945 FLAGS.referencedir, | 622 FLAGS.referencedir, |
| 946 selenium_constants.PLATFORM_SCREENSHOT_DIR, | 623 selenium_constants.PLATFORM_SCREENSHOT_DIR, |
| 947 "") | 624 "") |
| 625 |
| 626 # Launch HTTP server. |
| 627 http_server = LocalFileHTTPServer.StartServer(FLAGS.product_dir) |
| 948 | 628 |
| 949 # Open a new session to Selenium Remote Control | 629 if not http_server: |
| 950 selenium_session = SeleniumSession(FLAGS.verbose, FLAGS.java, | 630 print "Could not start a local http server with root." % FLAGS.product_dir |
| 951 os.path.abspath(FLAGS.selenium_server), | 631 return 1 |
| 952 FLAGS.servertimeout) | 632 |
| 953 if not selenium_session.http_server or not selenium_session.selenium_server: | 633 |
| 634 # Start Selenium Remote Control and Selenium Session Builder. |
| 635 sel_server_jar = os.path.abspath(FLAGS.selenium_server) |
| 636 sel_server = SeleniumRemoteControl.StartServer( |
| 637 FLAGS.verbose, FLAGS.java, sel_server_jar, |
| 638 FLAGS.servertimeout) |
| 639 |
| 640 if not sel_server: |
| 641 print "Could not start selenium server at %s." % sel_server_jar |
| 954 return 1 | 642 return 1 |
| 955 | 643 |
| 644 session_builder = SeleniumSessionBuilder( |
| 645 sel_server.selenium_port, |
| 646 int(FLAGS.servertimeout) * 1000, |
| 647 http_server.http_port, |
| 648 FLAGS.browserpath) |
| 649 |
| 650 all_tests_passed = True |
| 651 # Test browsers. |
| 956 for browser in FLAGS.browser: | 652 for browser in FLAGS.browser: |
| 957 if browser in set(selenium_constants.SELENIUM_BROWSER_SET): | 653 if browser in set(selenium_constants.SELENIUM_BROWSER_SET): |
| 958 test_list = [] | 654 test_list = GetTestsForBrowser(browser, FLAGS.testprefix, |
| 959 result = selenium_session.TestBrowser(browser, test_list, | 655 FLAGS.testsuffixes) |
| 960 FLAGS.testprefix, | |
| 961 FLAGS.testsuffixes, | |
| 962 int(FLAGS.servertimeout) * 1000) | |
| 963 | 656 |
| 964 # Compare screenshots | 657 result = TestBrowser(session_builder, browser, test_list) |
| 965 compare_result = CompareScreenshots(browser, | 658 |
| 966 test_list, | 659 if not result.wasSuccessful(): |
| 967 FLAGS.screenshots, | |
| 968 FLAGS.screenshotsdir, | |
| 969 FLAGS.screencompare, | |
| 970 FLAGS.verbose) | |
| 971 if not result.wasSuccessful() or not compare_result.WasSuccessful(): | |
| 972 all_tests_passed = False | 660 all_tests_passed = False |
| 973 # Log results | 661 |
| 974 print "Results for %s:" % browser | 662 # Log non-succesful tests, for convenience. |
| 975 print " %d tests run." % (result.testsRun + compare_result.tests_run) | 663 print "" |
| 976 print " %d errors." % (len(result.errors) + len(compare_result.errors)) | 664 print "Failures for %s:" % browser |
| 977 print " %d failures.\n" % (len(result.failures) + | 665 print "[Selenium tests]" |
| 978 len(compare_result.failures)) | 666 for entry in test_list: |
| 667 if type(entry) == tuple: |
| 668 test = entry[0] |
| 669 else: |
| 670 test = entry |
| 671 |
| 672 if test in result.results: |
| 673 if result.results[test] != 'PASS': |
| 674 print test.name |
| 675 |
| 676 print "" |
| 677 print "[Perceptual Diff tests]" |
| 678 for entry in test_list: |
| 679 if type(entry) == tuple: |
| 680 pdiff_test = entry[1] |
| 681 if pdiff_test in result.results: |
| 682 if result.results[pdiff_test] != 'PASS': |
| 683 print pdiff_test.name |
| 684 |
| 685 |
| 686 # Log summary results. |
| 687 print "" |
| 688 print "Summary for %s:" % browser |
| 689 print " %d tests run." % result.testsRun |
| 690 print " %d errors." % len(result.errors) |
| 691 print " %d failures.\n" % len(result.failures) |
| 979 | 692 |
| 980 else: | 693 else: |
| 981 print "ERROR: Browser %s is invalid." % browser | 694 print "ERROR: Browser %s is invalid." % browser |
| 982 print "Run with --help to view list of supported browsers.\n" | 695 print "Run with --help to view list of supported browsers.\n" |
| 983 all_tests_passed = False | 696 all_tests_passed = False |
| 984 | 697 |
| 985 # Wrap up session | 698 # Shut down remote control |
| 986 selenium_session.TearDown() | 699 shutdown_session = selenium.selenium("localhost", |
| 700 sel_server.selenium_port, "*firefox", |
| 701 "http://%s:%d" % (socket.gethostname(), http_server.http_port)) |
| 702 shutdown_session.shut_down_selenium_server() |
| 987 | 703 |
| 988 if all_tests_passed: | 704 if all_tests_passed: |
| 989 # All tests successful. | 705 # All tests successful. |
| 990 return 0 | 706 return 0 |
| 991 else: | 707 else: |
| 992 # Return error code 1. | 708 # Return error code 1. |
| 993 return 1 | 709 return 1 |
| 994 | 710 |
| 995 def GetChromePath(): | |
| 996 value = None | |
| 997 if sys.platform == "win32" or sys.platform == "cygwin": | |
| 998 import _winreg | |
| 999 try: | |
| 1000 key = _winreg.OpenKey(_winreg.HKEY_CLASSES_ROOT, | |
| 1001 "Applications\\chrome.exe\\shell\\open\\command") | |
| 1002 (value, type) = _winreg.QueryValueEx(key, None) | |
| 1003 _winreg.CloseKey(key) | |
| 1004 except WindowsError: | |
| 1005 raise Exception("Unable to determine location for Chrome -- " | |
| 1006 "it is installed?") | |
| 1007 value = os.path.dirname(value) | |
| 1008 return value | |
| 1009 | |
| 1010 if __name__ == "__main__": | 711 if __name__ == "__main__": |
| 1011 remaining_argv = FLAGS(sys.argv) | 712 remaining_argv = FLAGS(sys.argv) |
| 1012 | 713 |
| 1013 # Setup the environment for Firefox | 714 # Setup the environment for Firefox |
| 1014 os.environ["MOZ_CRASHREPORTER_DISABLE"] = "1" | 715 os.environ["MOZ_CRASHREPORTER_DISABLE"] = "1" |
| 1015 os.environ["MOZ_PLUGIN_PATH"] = os.path.normpath(FLAGS.product_dir) | 716 os.environ["MOZ_PLUGIN_PATH"] = os.path.normpath(FLAGS.product_dir) |
| 1016 | 717 |
| 1017 # Setup the path for chrome. | 718 # Setup the path for chrome. |
| 1018 chrome_path = GetChromePath() | 719 chrome_path = GetChromePath() |
| 1019 if chrome_path: | 720 if chrome_path: |
| 1020 if os.environ.get("PATH"): | 721 if os.environ.get("PATH"): |
| 1021 os.environ["PATH"] = os.pathsep.join([os.environ["PATH"], chrome_path]) | 722 os.environ["PATH"] = os.pathsep.join([os.environ["PATH"], chrome_path]) |
| 1022 else: | 723 else: |
| 1023 os.environ["PATH"] = chrome_path | 724 os.environ["PATH"] = chrome_path |
| 1024 | 725 |
| 1025 # Setup the LD_LIBRARY_PATH on Linux. | 726 # Setup the LD_LIBRARY_PATH on Linux. |
| 1026 if sys.platform[:5] == "linux": | 727 if sys.platform[:5] == "linux": |
| 1027 if os.environ.get("LD_LIBRARY_PATH"): | 728 if os.environ.get("LD_LIBRARY_PATH"): |
| 1028 os.environ["LD_LIBRARY_PATH"] = os.pathsep.join( | 729 os.environ["LD_LIBRARY_PATH"] = os.pathsep.join( |
| 1029 [os.environ["LD_LIBRARY_PATH"], os.path.normpath(FLAGS.product_dir)]) | 730 [os.environ["LD_LIBRARY_PATH"], os.path.normpath(FLAGS.product_dir)]) |
| 1030 else: | 731 else: |
| 1031 os.environ["LD_LIBRARY_PATH"] = os.path.normpath(FLAGS.product_dir) | 732 os.environ["LD_LIBRARY_PATH"] = os.path.normpath(FLAGS.product_dir) |
| 1032 | 733 |
| 1033 sys.exit(main(remaining_argv)) | 734 sys.exit(main(remaining_argv)) |
| OLD | NEW |