• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
34# global imports
35from contextlib import contextmanager
36import io
37import shlex
38import sys
39import typing
40
41# pip imports
42import pytest
43
44# local imports
45import app_startup_runner as asr
46
47#
48# Argument Parsing Helpers
49#
50
51@contextmanager
52def ignore_stdout_stderr():
53  """Ignore stdout/stderr output for duration of this context."""
54  old_stdout = sys.stdout
55  old_stderr = sys.stderr
56  sys.stdout = io.StringIO()
57  sys.stderr = io.StringIO()
58  try:
59    yield
60  finally:
61    sys.stdout = old_stdout
62    sys.stderr = old_stderr
63
64@contextmanager
65def argparse_bad_argument(msg):
66  """
67  Assert that a SystemExit is raised when executing this context.
68  If the assertion fails, print the message 'msg'.
69  """
70  with pytest.raises(SystemExit, message=msg):
71    with ignore_stdout_stderr():
72      yield
73
74def assert_bad_argument(args, msg):
75  """
76  Assert that the command line arguments in 'args' are malformed.
77  Prints 'msg' if the assertion fails.
78  """
79  with argparse_bad_argument(msg):
80    parse_args(args)
81
82def parse_args(args):
83  """
84  :param args: command-line like arguments as a single string
85  :return:  dictionary of parsed key/values
86  """
87  # "-a b -c d"    => ['-a', 'b', '-c', 'd']
88  return vars(asr.parse_options(shlex.split(args)))
89
90def default_dict_for_parsed_args(**kwargs):
91  """
92  # Combine it with all of the "optional" parameters' default values.
93  """
94  d = {'compiler_filters': None, 'simulate': False, 'debug': False, 'output': None, 'timeout': None, 'loop_count': 1, 'inodes': None}
95  d.update(kwargs)
96  return d
97
98def default_mock_dict_for_parsed_args(include_optional=True, **kwargs):
99  """
100  Combine default dict with all optional parameters with some mock required parameters.
101  """
102  d = {'packages': ['com.fake.package'], 'readaheads': ['warm']}
103  if include_optional:
104    d.update(default_dict_for_parsed_args())
105  d.update(kwargs)
106  return d
107
108def parse_optional_args(str):
109  """
110  Parse an argument string which already includes all the required arguments
111  in default_mock_dict_for_parsed_args.
112  """
113  req = "--package com.fake.package --readahead warm"
114  return parse_args("%s %s" %(req, str))
115
116def test_argparse():
117  # missing arguments
118  assert_bad_argument("", "-p and -r are required")
119  assert_bad_argument("-r warm", "-p is required")
120  assert_bad_argument("--readahead warm", "-p is required")
121  assert_bad_argument("-p com.fake.package", "-r is required")
122  assert_bad_argument("--package com.fake.package", "-r is required")
123
124  # required arguments are parsed correctly
125  ad = default_dict_for_parsed_args  # assert dict
126
127  assert parse_args("--package xyz --readahead warm") == ad(packages=['xyz'], readaheads=['warm'])
128  assert parse_args("-p xyz -r warm") == ad(packages=['xyz'], readaheads=['warm'])
129
130  assert parse_args("-p xyz -r warm -s") == ad(packages=['xyz'], readaheads=['warm'], simulate=True)
131  assert parse_args("-p xyz -r warm --simulate") == ad(packages=['xyz'], readaheads=['warm'], simulate=True)
132
133  # optional arguments are parsed correctly.
134  mad = default_mock_dict_for_parsed_args  # mock assert dict
135  assert parse_optional_args("--output filename.csv") == mad(output='filename.csv')
136  assert parse_optional_args("-o filename.csv") == mad(output='filename.csv')
137
138  assert parse_optional_args("--timeout 123") == mad(timeout=123)
139  assert parse_optional_args("-t 456") == mad(timeout=456)
140
141  assert parse_optional_args("--loop-count 123") == mad(loop_count=123)
142  assert parse_optional_args("-lc 456") == mad(loop_count=456)
143
144  assert parse_optional_args("--inodes bar") == mad(inodes="bar")
145  assert parse_optional_args("-in baz") == mad(inodes="baz")
146
147
148def generate_run_combinations(*args):
149  # expand out the generator values so that assert x == y works properly.
150  return [i for i in asr.generate_run_combinations(*args)]
151
152def test_generate_run_combinations():
153  blank_nd = typing.NamedTuple('Blank')
154  assert generate_run_combinations(blank_nd, {}) == [()], "empty"
155  assert generate_run_combinations(blank_nd, {'a' : ['a1', 'a2']}) == [()], "empty filter"
156  a_nd = typing.NamedTuple('A', [('a', str)])
157  assert generate_run_combinations(a_nd, {'a': None}) == [(None,)], "None"
158  assert generate_run_combinations(a_nd, {'a': ['a1', 'a2']}) == [('a1',), ('a2',)], "one item"
159  assert generate_run_combinations(a_nd,
160                                   {'a' : ['a1', 'a2'], 'b': ['b1', 'b2']}) == [('a1',), ('a2',)],\
161      "one item filter"
162  ab_nd = typing.NamedTuple('AB', [('a', str), ('b', str)])
163  assert generate_run_combinations(ab_nd,
164                                   {'a': ['a1', 'a2'],
165                                    'b': ['b1', 'b2']}) == [ab_nd('a1', 'b1'),
166                                                            ab_nd('a1', 'b2'),
167                                                            ab_nd('a2', 'b1'),
168                                                            ab_nd('a2', 'b2')],\
169      "two items"
170
171  assert generate_run_combinations(ab_nd,
172                                   {'as': ['a1', 'a2'],
173                                    'bs': ['b1', 'b2']}) == [ab_nd('a1', 'b1'),
174                                                             ab_nd('a1', 'b2'),
175                                                             ab_nd('a2', 'b1'),
176                                                             ab_nd('a2', 'b2')],\
177      "two items plural"
178
179def test_key_to_cmdline_flag():
180  assert asr.key_to_cmdline_flag("abc") == "--abc"
181  assert asr.key_to_cmdline_flag("foos") == "--foo"
182  assert asr.key_to_cmdline_flag("ba_r") == "--ba-r"
183  assert asr.key_to_cmdline_flag("ba_zs") == "--ba-z"
184
185
186def test_make_script_command_with_temp_output():
187  cmd_str, tmp_file = asr.make_script_command_with_temp_output("fake_script", args=[], count=1)
188  with tmp_file:
189    assert cmd_str == ["fake_script", "--count", "1", "--output", tmp_file.name]
190
191  cmd_str, tmp_file = asr.make_script_command_with_temp_output("fake_script", args=['a', 'b'], count=2)
192  with tmp_file:
193    assert cmd_str == ["fake_script", "a", "b", "--count", "2", "--output", tmp_file.name]
194
195def test_parse_run_script_csv_file():
196  # empty file -> empty list
197  f = io.StringIO("")
198  assert asr.parse_run_script_csv_file(f) == []
199
200  # common case
201  f = io.StringIO("1,2,3")
202  assert asr.parse_run_script_csv_file(f) == [1,2,3]
203
204  # ignore trailing comma
205  f = io.StringIO("1,2,3,4,5,")
206  assert asr.parse_run_script_csv_file(f) == [1,2,3,4,5]
207
208
209if __name__ == '__main__':
210  pytest.main()
211