1#!/usr/bin/env python3 2# 3# Copyright 2018, The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17 18""" 19Unit tests for the app_startup_runner.py script. 20 21Install: 22 $> sudo apt-get install python3-pytest ## OR 23 $> pip install -U pytest 24See also https://docs.pytest.org/en/latest/getting-started.html 25 26Usage: 27 $> ./app_startup_runner_test.py 28 $> pytest app_startup_runner_test.py 29 $> python -m pytest app_startup_runner_test.py 30 31See also https://docs.pytest.org/en/latest/usage.html 32""" 33 34import io 35import shlex 36import sys 37import typing 38# global imports 39from contextlib import contextmanager 40 41# local imports 42import app_startup_runner as asr 43# pip imports 44import pytest 45 46# 47# Argument Parsing Helpers 48# 49 50@contextmanager 51def ignore_stdout_stderr(): 52 """Ignore stdout/stderr output for duration of this context.""" 53 old_stdout = sys.stdout 54 old_stderr = sys.stderr 55 sys.stdout = io.StringIO() 56 sys.stderr = io.StringIO() 57 try: 58 yield 59 finally: 60 sys.stdout = old_stdout 61 sys.stderr = old_stderr 62 63@contextmanager 64def argparse_bad_argument(msg): 65 """ 66 Assert that a SystemExit is raised when executing this context. 67 If the assertion fails, print the message 'msg'. 68 """ 69 with pytest.raises(SystemExit, message=msg): 70 with ignore_stdout_stderr(): 71 yield 72 73def assert_bad_argument(args, msg): 74 """ 75 Assert that the command line arguments in 'args' are malformed. 76 Prints 'msg' if the assertion fails. 77 """ 78 with argparse_bad_argument(msg): 79 parse_args(args) 80 81def parse_args(args): 82 """ 83 :param args: command-line like arguments as a single string 84 :return: dictionary of parsed key/values 85 """ 86 # "-a b -c d" => ['-a', 'b', '-c', 'd'] 87 return vars(asr.parse_options(shlex.split(args))) 88 89def default_dict_for_parsed_args(**kwargs): 90 """ 91 # Combine it with all of the "optional" parameters' default values. 92 """ 93 d = {'compiler_filters': None, 'simulate': False, 'debug': False, 94 'output': None, 'timeout': 10, 'loop_count': 1, 'inodes': None, 95 'trace_duration': None, 'compiler_type': asr.CompilerType.DEVICE} 96 d.update(kwargs) 97 return d 98 99def default_mock_dict_for_parsed_args(include_optional=True, **kwargs): 100 """ 101 Combine default dict with all optional parameters with some mock required parameters. 102 """ 103 d = {'packages': ['com.fake.package'], 'readaheads': ['warm']} 104 if include_optional: 105 d.update(default_dict_for_parsed_args()) 106 d.update(kwargs) 107 return d 108 109def parse_optional_args(str): 110 """ 111 Parse an argument string which already includes all the required arguments 112 in default_mock_dict_for_parsed_args. 113 """ 114 req = "--package com.fake.package --readahead warm" 115 return parse_args("%s %s" % (req, str)) 116 117def test_argparse(): 118 # missing arguments 119 assert_bad_argument("", "-p and -r are required") 120 assert_bad_argument("-r warm", "-p is required") 121 assert_bad_argument("--readahead warm", "-p is required") 122 assert_bad_argument("-p com.fake.package", "-r is required") 123 assert_bad_argument("--package com.fake.package", "-r is required") 124 125 # required arguments are parsed correctly 126 ad = default_dict_for_parsed_args # assert dict 127 128 assert parse_args("--package xyz --readahead warm") == ad(packages=['xyz'], 129 readaheads=['warm']) 130 assert parse_args("-p xyz -r warm") == ad(packages=['xyz'], 131 readaheads=['warm']) 132 133 assert parse_args("-p xyz -r warm -s") == ad(packages=['xyz'], 134 readaheads=['warm'], 135 simulate=True) 136 assert parse_args("-p xyz -r warm --simulate") == ad(packages=['xyz'], 137 readaheads=['warm'], 138 simulate=True) 139 140 # optional arguments are parsed correctly. 141 mad = default_mock_dict_for_parsed_args # mock assert dict 142 assert parse_optional_args("--output filename.csv") == mad( 143 output='filename.csv') 144 assert parse_optional_args("-o filename.csv") == mad(output='filename.csv') 145 146 assert parse_optional_args("--timeout 123") == mad(timeout=123) 147 assert parse_optional_args("-t 456") == mad(timeout=456) 148 149 assert parse_optional_args("--loop-count 123") == mad(loop_count=123) 150 assert parse_optional_args("-lc 456") == mad(loop_count=456) 151 152 assert parse_optional_args("--inodes bar") == mad(inodes="bar") 153 assert parse_optional_args("-in baz") == mad(inodes="baz") 154 155 156 157def test_key_to_cmdline_flag(): 158 assert asr.key_to_cmdline_flag("abc") == "--abc" 159 assert asr.key_to_cmdline_flag("foos") == "--foo" 160 assert asr.key_to_cmdline_flag("ba_r") == "--ba-r" 161 assert asr.key_to_cmdline_flag("ba_zs") == "--ba-z" 162 163def test_parse_run_script_csv_file(): 164 # empty file -> empty list 165 f = io.StringIO("") 166 assert asr.parse_run_script_csv_file(f) == None 167 168 # common case 169 f = io.StringIO("TotalTime_ms,Displayed_ms\n1,2") 170 df = asr.DataFrame({'TotalTime_ms': [1], 'Displayed_ms': [2]}) 171 172 pf = asr.parse_run_script_csv_file(f) 173 assert pf == df 174 175if __name__ == '__main__': 176 pytest.main() 177