1*3f982cf4SFabien Sanglard#!/usr/bin/env python3 2*3f982cf4SFabien Sanglard# Copyright 2021 The Chromium Authors. All rights reserved. 3*3f982cf4SFabien Sanglard# Use of this source code is governed by a BSD-style license that can be 4*3f982cf4SFabien Sanglard# found in the LICENSE file. 5*3f982cf4SFabien Sanglard""" 6*3f982cf4SFabien SanglardThis script is intended to cover end to end testing for the standalone sender 7*3f982cf4SFabien Sanglardand receiver executables in cast. This ensures that the basic functionality of 8*3f982cf4SFabien Sanglardthese executables is not impaired, such as the TLS/UDP connections and encoding 9*3f982cf4SFabien Sanglardand decoding video. 10*3f982cf4SFabien Sanglard""" 11*3f982cf4SFabien Sanglard 12*3f982cf4SFabien Sanglardimport argparse 13*3f982cf4SFabien Sanglardimport os 14*3f982cf4SFabien Sanglardimport pathlib 15*3f982cf4SFabien Sanglardimport logging 16*3f982cf4SFabien Sanglardimport subprocess 17*3f982cf4SFabien Sanglardimport sys 18*3f982cf4SFabien Sanglardimport time 19*3f982cf4SFabien Sanglardimport unittest 20*3f982cf4SFabien Sanglardimport ssl 21*3f982cf4SFabien Sanglardfrom collections import namedtuple 22*3f982cf4SFabien Sanglard 23*3f982cf4SFabien Sanglardfrom enum import IntEnum, IntFlag 24*3f982cf4SFabien Sanglardfrom urllib import request 25*3f982cf4SFabien Sanglard 26*3f982cf4SFabien Sanglard# Environment variables that can be overridden to set test properties. 27*3f982cf4SFabien SanglardROOT_ENVVAR = 'OPENSCREEN_ROOT_DIR' 28*3f982cf4SFabien SanglardBUILD_ENVVAR = 'OPENSCREEN_BUILD_DIR' 29*3f982cf4SFabien SanglardLIBAOM_ENVVAR = 'OPENSCREEN_HAVE_LIBAOM' 30*3f982cf4SFabien Sanglard 31*3f982cf4SFabien SanglardTEST_VIDEO_NAME = 'Contador_Glam.mp4' 32*3f982cf4SFabien Sanglard# NOTE: we use the HTTP protocol instead of HTTPS due to certificate issues 33*3f982cf4SFabien Sanglard# in the legacy urllib.request API. 34*3f982cf4SFabien SanglardTEST_VIDEO_URL = ('https://storage.googleapis.com/openscreen_standalone/' + 35*3f982cf4SFabien Sanglard TEST_VIDEO_NAME) 36*3f982cf4SFabien Sanglard 37*3f982cf4SFabien SanglardPROCESS_TIMEOUT = 15 # seconds 38*3f982cf4SFabien Sanglard 39*3f982cf4SFabien Sanglard# Open Screen test certificates expire after 3 days. We crop this slightly (by 40*3f982cf4SFabien Sanglard# 8 hours) to account for potential errors in time calculations. 41*3f982cf4SFabien SanglardCERT_EXPIRY_AGE = (3 * 24 - 8) * 60 * 60 42*3f982cf4SFabien Sanglard 43*3f982cf4SFabien Sanglard# These properties are based on compiled settings in Open Screen, and should 44*3f982cf4SFabien Sanglard# not change without updating this file. 45*3f982cf4SFabien SanglardTEST_CERT_NAME = 'generated_root_cast_receiver.crt' 46*3f982cf4SFabien SanglardTEST_KEY_NAME = 'generated_root_cast_receiver.key' 47*3f982cf4SFabien SanglardSENDER_BINARY_NAME = 'cast_sender' 48*3f982cf4SFabien SanglardRECEIVER_BINARY_NAME = 'cast_receiver' 49*3f982cf4SFabien Sanglard 50*3f982cf4SFabien SanglardEXPECTED_RECEIVER_MESSAGES = [ 51*3f982cf4SFabien Sanglard "CastService is running.", "Found codec: opus (known to FFMPEG as opus)", 52*3f982cf4SFabien Sanglard "Successfully negotiated a session, creating SDL players.", 53*3f982cf4SFabien Sanglard "Receivers are currently destroying, resetting SDL players." 54*3f982cf4SFabien Sanglard] 55*3f982cf4SFabien Sanglard 56*3f982cf4SFabien Sanglardclass VideoCodec(IntEnum): 57*3f982cf4SFabien Sanglard """There are different messages printed by the receiver depending on the codec 58*3f982cf4SFabien Sanglard chosen. """ 59*3f982cf4SFabien Sanglard Vp8 = 0 60*3f982cf4SFabien Sanglard Vp9 = 1 61*3f982cf4SFabien Sanglard Av1 = 2 62*3f982cf4SFabien Sanglard 63*3f982cf4SFabien SanglardVIDEO_CODEC_SPECIFIC_RECEIVER_MESSAGES = [ 64*3f982cf4SFabien Sanglard "Found codec: vp8 (known to FFMPEG as vp8)", 65*3f982cf4SFabien Sanglard "Found codec: vp9 (known to FFMPEG as vp9)", 66*3f982cf4SFabien Sanglard "Found codec: libaom-av1 (known to FFMPEG as av1)" 67*3f982cf4SFabien Sanglard] 68*3f982cf4SFabien Sanglard 69*3f982cf4SFabien SanglardEXPECTED_SENDER_MESSAGES = [ 70*3f982cf4SFabien Sanglard "Launching Mirroring App on the Cast Receiver", 71*3f982cf4SFabien Sanglard "Max allowed media bitrate (audio + video) will be", 72*3f982cf4SFabien Sanglard "Contador_Glam.mp4 (starts in one second)...", 73*3f982cf4SFabien Sanglard "The video capturer has reached the end of the media stream.", 74*3f982cf4SFabien Sanglard "The audio capturer has reached the end of the media stream.", 75*3f982cf4SFabien Sanglard "Video complete. Exiting...", "Shutting down..." 76*3f982cf4SFabien Sanglard] 77*3f982cf4SFabien Sanglard 78*3f982cf4SFabien SanglardMISSING_LOG_MESSAGE = """Missing an expected message from either the sender 79*3f982cf4SFabien Sanglardor receiver. This either means that one of the binaries misbehaved, or you 80*3f982cf4SFabien Sanglardchanged or deleted one of the log messages used for validation. Please ensure 81*3f982cf4SFabien Sanglardthat the necessary log messages are left unchanged, or update this 82*3f982cf4SFabien Sanglardtest suite's expectations.""" 83*3f982cf4SFabien Sanglard 84*3f982cf4SFabien SanglardDESCRIPTION = """Runs end to end tests for the standalone Cast Streaming sender 85*3f982cf4SFabien Sanglardand receiver. By default, this script assumes it is being ran from a current 86*3f982cf4SFabien Sanglardworking directory inside Open Screen's source directory, and uses 87*3f982cf4SFabien Sanglard<root_dir>/out/Default as the build directory. To override these, set the 88*3f982cf4SFabien SanglardOPENSCREEN_ROOT_DIR and OPENSCREEN_BUILD_DIR environment variables. If the root 89*3f982cf4SFabien Sanglarddirectory is set and the build directory is not, 90*3f982cf4SFabien Sanglard<OPENSCREEN_ROOT_DIR>/out/Default will be used. In addition, if LibAOM is 91*3f982cf4SFabien Sanglardinstalled, one can choose to run AV1 tests by defining the 92*3f982cf4SFabien SanglardOPENSCREEN_HAVE_LIBAOM environment variable. 93*3f982cf4SFabien Sanglard 94*3f982cf4SFabien SanglardSee below for the the help output generated by the `unittest` package.""" 95*3f982cf4SFabien Sanglard 96*3f982cf4SFabien Sanglard 97*3f982cf4SFabien Sanglarddef _set_log_level(is_verbose): 98*3f982cf4SFabien Sanglard """Sets the logging level, either DEBUG or ERROR as appropriate.""" 99*3f982cf4SFabien Sanglard level = logging.DEBUG if is_verbose else logging.INFO 100*3f982cf4SFabien Sanglard logging.basicConfig(stream=sys.stdout, level=level) 101*3f982cf4SFabien Sanglard 102*3f982cf4SFabien Sanglard 103*3f982cf4SFabien Sanglarddef _get_loopback_adapter_name(): 104*3f982cf4SFabien Sanglard """Retrieves the name of the loopback adapter (lo on Linux/lo0 on Mac).""" 105*3f982cf4SFabien Sanglard if sys.platform == 'linux' or sys.platform == 'linux2': 106*3f982cf4SFabien Sanglard return 'lo' 107*3f982cf4SFabien Sanglard if sys.platform == 'darwin': 108*3f982cf4SFabien Sanglard return 'lo0' 109*3f982cf4SFabien Sanglard return None 110*3f982cf4SFabien Sanglard 111*3f982cf4SFabien Sanglard 112*3f982cf4SFabien Sanglarddef _get_file_age_in_seconds(path): 113*3f982cf4SFabien Sanglard """Get the age of a given file in seconds""" 114*3f982cf4SFabien Sanglard # Time is stored in seconds since epoch 115*3f982cf4SFabien Sanglard file_last_modified = 0 116*3f982cf4SFabien Sanglard if path.exists(): 117*3f982cf4SFabien Sanglard file_last_modified = path.stat().st_mtime 118*3f982cf4SFabien Sanglard return time.time() - file_last_modified 119*3f982cf4SFabien Sanglard 120*3f982cf4SFabien Sanglard 121*3f982cf4SFabien Sanglarddef _get_build_paths(): 122*3f982cf4SFabien Sanglard """Gets the root and build paths (either default or from the environment 123*3f982cf4SFabien Sanglard variables), and sets related paths to binaries and files.""" 124*3f982cf4SFabien Sanglard root_path = pathlib.Path( 125*3f982cf4SFabien Sanglard os.environ[ROOT_ENVVAR] if os.getenv(ROOT_ENVVAR) else subprocess. 126*3f982cf4SFabien Sanglard getoutput('git rev-parse --show-toplevel')) 127*3f982cf4SFabien Sanglard assert root_path.exists(), 'Could not find openscreen root!' 128*3f982cf4SFabien Sanglard 129*3f982cf4SFabien Sanglard build_path = pathlib.Path(os.environ[BUILD_ENVVAR]) if os.getenv( 130*3f982cf4SFabien Sanglard BUILD_ENVVAR) else root_path.joinpath('out', 131*3f982cf4SFabien Sanglard 'Default').resolve() 132*3f982cf4SFabien Sanglard assert build_path.exists(), 'Could not find openscreen build!' 133*3f982cf4SFabien Sanglard 134*3f982cf4SFabien Sanglard BuildPaths = namedtuple("BuildPaths", 135*3f982cf4SFabien Sanglard "root build test_video cast_receiver cast_sender") 136*3f982cf4SFabien Sanglard return BuildPaths(root = root_path, 137*3f982cf4SFabien Sanglard build = build_path, 138*3f982cf4SFabien Sanglard test_video = build_path.joinpath(TEST_VIDEO_NAME).resolve(), 139*3f982cf4SFabien Sanglard cast_receiver = build_path.joinpath(RECEIVER_BINARY_NAME).resolve(), 140*3f982cf4SFabien Sanglard cast_sender = build_path.joinpath(SENDER_BINARY_NAME).resolve() 141*3f982cf4SFabien Sanglard ) 142*3f982cf4SFabien Sanglard 143*3f982cf4SFabien Sanglard 144*3f982cf4SFabien Sanglardclass TestFlags(IntFlag): 145*3f982cf4SFabien Sanglard """ 146*3f982cf4SFabien Sanglard Test flags, primarily used to control sender and receiver configuration 147*3f982cf4SFabien Sanglard to test different features of the standalone libraries. 148*3f982cf4SFabien Sanglard """ 149*3f982cf4SFabien Sanglard UseRemoting = 1 150*3f982cf4SFabien Sanglard UseAndroidHack = 2 151*3f982cf4SFabien Sanglard 152*3f982cf4SFabien Sanglard 153*3f982cf4SFabien Sanglardclass StandaloneCastTest(unittest.TestCase): 154*3f982cf4SFabien Sanglard """ 155*3f982cf4SFabien Sanglard Test class for setting up and running end to end tests on the 156*3f982cf4SFabien Sanglard standalone sender and receiver binaries. This class uses the unittest 157*3f982cf4SFabien Sanglard package, so methods that are executed as tests all have named prefixed 158*3f982cf4SFabien Sanglard with "test_". 159*3f982cf4SFabien Sanglard 160*3f982cf4SFabien Sanglard This suite sets the current working directory to the root of the Open 161*3f982cf4SFabien Sanglard Screen repository, and references all files from the root directory. 162*3f982cf4SFabien Sanglard Generated certificates should always be in |cls.build_paths.root|. 163*3f982cf4SFabien Sanglard """ 164*3f982cf4SFabien Sanglard 165*3f982cf4SFabien Sanglard @classmethod 166*3f982cf4SFabien Sanglard def setUpClass(cls): 167*3f982cf4SFabien Sanglard """Shared setup method for all tests, handles one-time updates.""" 168*3f982cf4SFabien Sanglard cls.build_paths = _get_build_paths() 169*3f982cf4SFabien Sanglard os.chdir(cls.build_paths.root) 170*3f982cf4SFabien Sanglard cls.download_video() 171*3f982cf4SFabien Sanglard cls.generate_certificates() 172*3f982cf4SFabien Sanglard 173*3f982cf4SFabien Sanglard @classmethod 174*3f982cf4SFabien Sanglard def download_video(cls): 175*3f982cf4SFabien Sanglard """Downloads the test video from Google storage.""" 176*3f982cf4SFabien Sanglard if os.path.exists(cls.build_paths.test_video): 177*3f982cf4SFabien Sanglard logging.debug('Video already exists, skipping download...') 178*3f982cf4SFabien Sanglard return 179*3f982cf4SFabien Sanglard 180*3f982cf4SFabien Sanglard logging.debug('Downloading video from %s', TEST_VIDEO_URL) 181*3f982cf4SFabien Sanglard with request.urlopen(TEST_VIDEO_URL, context=ssl.SSLContext()) as url: 182*3f982cf4SFabien Sanglard with open(cls.build_paths.test_video, 'wb') as file: 183*3f982cf4SFabien Sanglard file.write(url.read()) 184*3f982cf4SFabien Sanglard 185*3f982cf4SFabien Sanglard @classmethod 186*3f982cf4SFabien Sanglard def generate_certificates(cls): 187*3f982cf4SFabien Sanglard """Generates test certificates using the cast receiver.""" 188*3f982cf4SFabien Sanglard cert_age = _get_file_age_in_seconds(pathlib.Path(TEST_CERT_NAME)) 189*3f982cf4SFabien Sanglard key_age = _get_file_age_in_seconds(pathlib.Path(TEST_KEY_NAME)) 190*3f982cf4SFabien Sanglard if cert_age < CERT_EXPIRY_AGE and key_age < CERT_EXPIRY_AGE: 191*3f982cf4SFabien Sanglard logging.debug('Credentials are up to date...') 192*3f982cf4SFabien Sanglard return 193*3f982cf4SFabien Sanglard 194*3f982cf4SFabien Sanglard logging.debug('Credentials out of date, generating new ones...') 195*3f982cf4SFabien Sanglard try: 196*3f982cf4SFabien Sanglard subprocess.check_output( 197*3f982cf4SFabien Sanglard [ 198*3f982cf4SFabien Sanglard cls.build_paths.cast_receiver, 199*3f982cf4SFabien Sanglard '-g', # Generate certificate and private key. 200*3f982cf4SFabien Sanglard '-v' # Enable verbose logging. 201*3f982cf4SFabien Sanglard ], 202*3f982cf4SFabien Sanglard stderr=subprocess.STDOUT) 203*3f982cf4SFabien Sanglard except subprocess.CalledProcessError as e: 204*3f982cf4SFabien Sanglard print('Generation failed with output: ', e.output.decode()) 205*3f982cf4SFabien Sanglard raise 206*3f982cf4SFabien Sanglard 207*3f982cf4SFabien Sanglard def launch_receiver(self): 208*3f982cf4SFabien Sanglard """Launches the receiver process with discovery disabled.""" 209*3f982cf4SFabien Sanglard logging.debug('Launching the receiver application...') 210*3f982cf4SFabien Sanglard loopback = _get_loopback_adapter_name() 211*3f982cf4SFabien Sanglard self.assertTrue(loopback) 212*3f982cf4SFabien Sanglard 213*3f982cf4SFabien Sanglard #pylint: disable = consider-using-with 214*3f982cf4SFabien Sanglard return subprocess.Popen( 215*3f982cf4SFabien Sanglard [ 216*3f982cf4SFabien Sanglard self.build_paths.cast_receiver, 217*3f982cf4SFabien Sanglard '-d', 218*3f982cf4SFabien Sanglard TEST_CERT_NAME, 219*3f982cf4SFabien Sanglard '-p', 220*3f982cf4SFabien Sanglard TEST_KEY_NAME, 221*3f982cf4SFabien Sanglard '-x', # Skip discovery, only necessary on Mac OS X. 222*3f982cf4SFabien Sanglard '-v', # Enable verbose logging. 223*3f982cf4SFabien Sanglard loopback 224*3f982cf4SFabien Sanglard ], 225*3f982cf4SFabien Sanglard stdout=subprocess.PIPE, 226*3f982cf4SFabien Sanglard stderr=subprocess.PIPE) 227*3f982cf4SFabien Sanglard 228*3f982cf4SFabien Sanglard def launch_sender(self, flags, codec=None): 229*3f982cf4SFabien Sanglard """Launches the sender process, running the test video file once.""" 230*3f982cf4SFabien Sanglard logging.debug('Launching the sender application...') 231*3f982cf4SFabien Sanglard command = [ 232*3f982cf4SFabien Sanglard self.build_paths.cast_sender, 233*3f982cf4SFabien Sanglard '127.0.0.1:8010', 234*3f982cf4SFabien Sanglard self.build_paths.test_video, 235*3f982cf4SFabien Sanglard '-d', 236*3f982cf4SFabien Sanglard TEST_CERT_NAME, 237*3f982cf4SFabien Sanglard '-n' # Only play the video once, and then exit. 238*3f982cf4SFabien Sanglard ] 239*3f982cf4SFabien Sanglard if TestFlags.UseAndroidHack in flags: 240*3f982cf4SFabien Sanglard command.append('-a') 241*3f982cf4SFabien Sanglard if TestFlags.UseRemoting in flags: 242*3f982cf4SFabien Sanglard command.append('-r') 243*3f982cf4SFabien Sanglard 244*3f982cf4SFabien Sanglard # The standalone sender sends VP8 if no codec command line argument is 245*3f982cf4SFabien Sanglard # passed. 246*3f982cf4SFabien Sanglard if codec: 247*3f982cf4SFabien Sanglard command.append('-c') 248*3f982cf4SFabien Sanglard if codec == VideoCodec.Vp8: 249*3f982cf4SFabien Sanglard command.append('vp8') 250*3f982cf4SFabien Sanglard elif codec == VideoCodec.Vp9: 251*3f982cf4SFabien Sanglard command.append('vp9') 252*3f982cf4SFabien Sanglard else: 253*3f982cf4SFabien Sanglard self.assertTrue(codec == VideoCodec.Av1) 254*3f982cf4SFabien Sanglard command.append('av1') 255*3f982cf4SFabien Sanglard 256*3f982cf4SFabien Sanglard #pylint: disable = consider-using-with 257*3f982cf4SFabien Sanglard return subprocess.Popen(command, 258*3f982cf4SFabien Sanglard stdout=subprocess.PIPE, 259*3f982cf4SFabien Sanglard stderr=subprocess.PIPE) 260*3f982cf4SFabien Sanglard 261*3f982cf4SFabien Sanglard def check_logs(self, logs, codec=None): 262*3f982cf4SFabien Sanglard """Checks that the outputted logs contain expected behavior.""" 263*3f982cf4SFabien Sanglard 264*3f982cf4SFabien Sanglard # If a codec was not provided, we should make sure that the standalone 265*3f982cf4SFabien Sanglard # sender sent VP8. 266*3f982cf4SFabien Sanglard if codec == None: 267*3f982cf4SFabien Sanglard codec = VideoCodec.Vp8 268*3f982cf4SFabien Sanglard 269*3f982cf4SFabien Sanglard for message in (EXPECTED_RECEIVER_MESSAGES + 270*3f982cf4SFabien Sanglard [VIDEO_CODEC_SPECIFIC_RECEIVER_MESSAGES[codec]]): 271*3f982cf4SFabien Sanglard self.assertTrue( 272*3f982cf4SFabien Sanglard message in logs[0], 273*3f982cf4SFabien Sanglard 'Missing log message: {}.\n{}'.format(message, 274*3f982cf4SFabien Sanglard MISSING_LOG_MESSAGE)) 275*3f982cf4SFabien Sanglard for message in EXPECTED_SENDER_MESSAGES: 276*3f982cf4SFabien Sanglard self.assertTrue( 277*3f982cf4SFabien Sanglard message in logs[1], 278*3f982cf4SFabien Sanglard 'Missing log message: {}.\n{}'.format(message, 279*3f982cf4SFabien Sanglard MISSING_LOG_MESSAGE)) 280*3f982cf4SFabien Sanglard for log, prefix in logs, ["[ERROR:", "[FATAL:"]: 281*3f982cf4SFabien Sanglard self.assertTrue(prefix not in log, "Logs contained an error") 282*3f982cf4SFabien Sanglard logging.debug('Finished validating log output') 283*3f982cf4SFabien Sanglard 284*3f982cf4SFabien Sanglard def get_output(self, flags, codec=None): 285*3f982cf4SFabien Sanglard """Launches the sender and receiver, and handles exit output.""" 286*3f982cf4SFabien Sanglard receiver_process = self.launch_receiver() 287*3f982cf4SFabien Sanglard logging.debug('Letting the receiver start up...') 288*3f982cf4SFabien Sanglard time.sleep(3) 289*3f982cf4SFabien Sanglard sender_process = self.launch_sender(flags, codec) 290*3f982cf4SFabien Sanglard 291*3f982cf4SFabien Sanglard logging.debug('Launched sender PID %i and receiver PID %i...', 292*3f982cf4SFabien Sanglard sender_process.pid, receiver_process.pid) 293*3f982cf4SFabien Sanglard logging.debug('collating output...') 294*3f982cf4SFabien Sanglard output = (receiver_process.communicate( 295*3f982cf4SFabien Sanglard timeout=PROCESS_TIMEOUT)[1].decode('utf-8'), 296*3f982cf4SFabien Sanglard sender_process.communicate( 297*3f982cf4SFabien Sanglard timeout=PROCESS_TIMEOUT)[1].decode('utf-8')) 298*3f982cf4SFabien Sanglard 299*3f982cf4SFabien Sanglard # TODO(issuetracker.google.com/194292855): standalones should exit zero. 300*3f982cf4SFabien Sanglard # Remoting causes the sender to exit with code -4. 301*3f982cf4SFabien Sanglard if not TestFlags.UseRemoting in flags: 302*3f982cf4SFabien Sanglard self.assertEqual(sender_process.returncode, 0, 303*3f982cf4SFabien Sanglard 'sender had non-zero exit code') 304*3f982cf4SFabien Sanglard return output 305*3f982cf4SFabien Sanglard 306*3f982cf4SFabien Sanglard def test_golden_case(self): 307*3f982cf4SFabien Sanglard """Tests that when settings are normal, things work end to end.""" 308*3f982cf4SFabien Sanglard output = self.get_output([]) 309*3f982cf4SFabien Sanglard self.check_logs(output) 310*3f982cf4SFabien Sanglard 311*3f982cf4SFabien Sanglard def test_remoting(self): 312*3f982cf4SFabien Sanglard """Tests that basic remoting works.""" 313*3f982cf4SFabien Sanglard output = self.get_output(TestFlags.UseRemoting) 314*3f982cf4SFabien Sanglard self.check_logs(output) 315*3f982cf4SFabien Sanglard 316*3f982cf4SFabien Sanglard def test_with_android_hack(self): 317*3f982cf4SFabien Sanglard """Tests that things work when the Android RTP hack is enabled.""" 318*3f982cf4SFabien Sanglard output = self.get_output(TestFlags.UseAndroidHack) 319*3f982cf4SFabien Sanglard self.check_logs(output) 320*3f982cf4SFabien Sanglard 321*3f982cf4SFabien Sanglard def test_vp8_flag(self): 322*3f982cf4SFabien Sanglard """Tests that the VP8 flag works with standard settings.""" 323*3f982cf4SFabien Sanglard output = self.get_output([], VideoCodec.Vp8) 324*3f982cf4SFabien Sanglard self.check_logs(output, VideoCodec.Vp8) 325*3f982cf4SFabien Sanglard 326*3f982cf4SFabien Sanglard def test_vp9_flag(self): 327*3f982cf4SFabien Sanglard """Tests that the VP9 flag works with standard settings.""" 328*3f982cf4SFabien Sanglard output = self.get_output([], VideoCodec.Vp9) 329*3f982cf4SFabien Sanglard self.check_logs(output, VideoCodec.Vp9) 330*3f982cf4SFabien Sanglard 331*3f982cf4SFabien Sanglard @unittest.skipUnless(os.getenv(LIBAOM_ENVVAR), 332*3f982cf4SFabien Sanglard 'Skipping AV1 test since LibAOM not installed.') 333*3f982cf4SFabien Sanglard def test_av1_flag(self): 334*3f982cf4SFabien Sanglard """Tests that the AV1 flag works with standard settings.""" 335*3f982cf4SFabien Sanglard output = self.get_output([], VideoCodec.Av1) 336*3f982cf4SFabien Sanglard self.check_logs(output, VideoCodec.Av1) 337*3f982cf4SFabien Sanglard 338*3f982cf4SFabien Sanglard 339*3f982cf4SFabien Sanglarddef parse_args(): 340*3f982cf4SFabien Sanglard """Parses the command line arguments and sets up the logging module.""" 341*3f982cf4SFabien Sanglard # NOTE for future developers: the `unittest` module will complain if it is 342*3f982cf4SFabien Sanglard # passed any args that it doesn't understand. If any Open Screen-specific 343*3f982cf4SFabien Sanglard # command line arguments are added in the future, they should be cropped 344*3f982cf4SFabien Sanglard # from sys.argv before |unittest.main()| is called. 345*3f982cf4SFabien Sanglard parser = argparse.ArgumentParser(description=DESCRIPTION) 346*3f982cf4SFabien Sanglard parser.add_argument('-v', 347*3f982cf4SFabien Sanglard '--verbose', 348*3f982cf4SFabien Sanglard help='enable debug logging', 349*3f982cf4SFabien Sanglard action='store_true') 350*3f982cf4SFabien Sanglard 351*3f982cf4SFabien Sanglard parsed_args = parser.parse_args(sys.argv[1:]) 352*3f982cf4SFabien Sanglard _set_log_level(parsed_args.verbose) 353*3f982cf4SFabien Sanglard 354*3f982cf4SFabien Sanglard 355*3f982cf4SFabien Sanglardif __name__ == '__main__': 356*3f982cf4SFabien Sanglard parse_args() 357*3f982cf4SFabien Sanglard unittest.main() 358