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