Skip to content

Commit ffa9cd3

Browse files
committed
feat: add py_unittest in casp and refactor butler
1 parent 5c8c2ba commit ffa9cd3

File tree

3 files changed

+103
-24
lines changed

3 files changed

+103
-24
lines changed

butler.py

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,30 @@ def _setup_args_for_remote(parser):
9898
subparsers.add_parser('reboot', help='Reboot with `sudo reboot`.')
9999

100100

101+
def _add_py_unittest_subparser(toplevel_subparsers):
102+
"""Adds a parser for the `py_unittest` command."""
103+
parser_py_unittest = toplevel_subparsers.add_parser(
104+
'py_unittest', help='Run Python unit tests.')
105+
parser_py_unittest.add_argument(
106+
'-p', '--pattern', help='Pattern for test files. Default is *_test.py.')
107+
parser_py_unittest.add_argument(
108+
'-u',
109+
'--unsuppress-output',
110+
action='store_true',
111+
help='Unsuppress output from `print`. Good for debugging.')
112+
parser_py_unittest.add_argument(
113+
'-m', '--parallel', action='store_true', help='Run tests in parallel.')
114+
parser_py_unittest.add_argument(
115+
'-v', '--verbose', action='store_true', help='Print logs from tests.')
116+
parser_py_unittest.add_argument(
117+
'-t',
118+
'--target',
119+
required=True,
120+
choices=['appengine', 'core', 'modules', 'cli'])
121+
parser_py_unittest.add_argument(
122+
'-c', '--config-dir', help='Config dir to use for module tests.')
123+
124+
101125
def _add_lint_subparser(toplevel_subparsers):
102126
"""Adds a parser for the `lint` command."""
103127
parser = toplevel_subparsers.add_parser(
@@ -298,24 +322,6 @@ def main():
298322
help=('Install all required dependencies for running an appengine, a bot,'
299323
'and a mapreduce locally.'))
300324

301-
parser_py_unittest = subparsers.add_parser(
302-
'py_unittest', help='Run Python unit tests.')
303-
parser_py_unittest.add_argument(
304-
'-p', '--pattern', help='Pattern for test files. Default is *_test.py.')
305-
parser_py_unittest.add_argument(
306-
'-u',
307-
'--unsuppress-output',
308-
action='store_true',
309-
help='Unsuppress output from `print`. Good for debugging.')
310-
parser_py_unittest.add_argument(
311-
'-m', '--parallel', action='store_true', help='Run tests in parallel.')
312-
parser_py_unittest.add_argument(
313-
'-v', '--verbose', action='store_true', help='Print logs from tests.')
314-
parser_py_unittest.add_argument(
315-
'-t', '--target', required=True, choices=['appengine', 'core', 'modules'])
316-
parser_py_unittest.add_argument(
317-
'-c', '--config-dir', help='Config dir to use for module tests.')
318-
319325
parser_js_unittest = subparsers.add_parser(
320326
'js_unittest', help='Run Javascript unit tests.')
321327
parser_js_unittest.add_argument(
@@ -448,6 +454,7 @@ def main():
448454
default='us-central',
449455
help='Location for App Engine.')
450456

457+
_add_py_unittest_subparser(subparsers)
451458
_add_lint_subparser(subparsers)
452459
_add_format_subparser(subparsers)
453460
_add_integration_tests_subparsers(subparsers)

cli/casp/src/casp/commands/py_unittest.py

Lines changed: 74 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,83 @@
88
#
99
# Unless required by applicable law or agreed to in writing, software
1010
# distributed under the License is distributed on an "AS IS" BASIS,
11-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.S
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
"""Py unittest command."""
14+
"""Run Python unit tests command."""
1515

16+
import subprocess
17+
import sys
18+
19+
from casp.utils import local_butler
1620
import click
1721

1822

19-
@click.command(name='py_unittest', help='Run Python unit tests.')
20-
def cli():
21-
"""Run Python unit tests."""
22-
click.echo('To be implemented...')
23+
@click.command(
24+
name='py_unittest',
25+
help=('Runs Python unit tests. '
26+
'You can specify a pattern for test files, '
27+
'run tests in parallel, unsuppress output, '
28+
'or print verbose logs.'))
29+
@click.option(
30+
'--pattern',
31+
'-p',
32+
help='Pattern for test files. Default is *_test.py.')
33+
@click.option(
34+
'--unsuppress-output',
35+
'-u',
36+
is_flag=True,
37+
default=False,
38+
help='Unsuppress output from `print`. Good for debugging.')
39+
@click.option(
40+
'--parallel',
41+
'-m',
42+
is_flag=True,
43+
default=False,
44+
help='Run tests in parallel.')
45+
@click.option(
46+
'--verbose',
47+
'-v',
48+
is_flag=True,
49+
default=False,
50+
help='Print logs from tests.')
51+
@click.option(
52+
'--target',
53+
'-t',
54+
required=True,
55+
type=click.Choice(['appengine', 'core', 'modules', 'cli']),
56+
help='The target for the unit tests.')
57+
@click.option(
58+
'--config-dir',
59+
'-c',
60+
help='Config directory to use for module tests.')
61+
def cli(pattern: str, unsuppress_output: bool, parallel: bool, verbose: bool,
62+
target: str, config_dir: str) -> None:
63+
"""Runs Python unit tests."""
64+
try:
65+
arguments = {}
66+
arguments['target'] = target
67+
if pattern:
68+
arguments['pattern'] = pattern
69+
if unsuppress_output:
70+
arguments['unsuppress_output'] = None
71+
if parallel:
72+
arguments['parallel'] = None
73+
if verbose:
74+
arguments['verbose'] = None
75+
if config_dir:
76+
arguments['config_dir'] = config_dir
77+
78+
command = local_butler.build_command('py_unittest', **arguments)
79+
except FileNotFoundError:
80+
click.echo('butler.py not found in this directory.', err=True)
81+
sys.exit(1)
82+
83+
try:
84+
subprocess.run(command, check=True)
85+
except FileNotFoundError:
86+
click.echo('python not found in PATH.', err=True)
87+
sys.exit(1)
88+
except subprocess.CalledProcessError as e:
89+
click.echo(f'Error running butler.py py_unittest: {e}', err=True)
90+
sys.exit(1)

src/local/butler/py_unittest.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
'tests', 'appengine')
3434
CORE_TEST_DIRECTORY = os.path.join('src', 'clusterfuzz', '_internal', 'tests',
3535
'core')
36+
CLI_TEST_DIRECTORY = os.path.join('cli', 'casp', 'src', 'casp', 'tests')
3637
SLOW_TEST_THRESHOLD = 2 # In seconds.
3738
TESTS_TIMEOUT = 20 * 60 # In seconds.
3839

@@ -250,6 +251,9 @@ def execute(args):
250251

251252
elif args.target == 'core':
252253
test_directory = CORE_TEST_DIRECTORY
254+
elif args.target == 'cli':
255+
test_directory = CLI_TEST_DIRECTORY
256+
top_level_dir = None
253257
else:
254258
# Config module tests.
255259
os.environ['CONFIG_DIR_OVERRIDE'] = args.config_dir

0 commit comments

Comments
 (0)