flaky test: src/tests/maasperf/cli/test_machines.py::test_perf_list_machines_CLI
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
MAAS |
Fix Released
|
Medium
|
Adam Collard |
Bug Description
The test fails if the random profile name starts with a `-`, which is interpreted as an option:
_______
[gw3] linux -- Python 3.10.6 /run/build/
self = ArgumentParser(
args = ['-uNIDFeflx', 'machines', 'read'], namespace = Namespace(
def parse_known_
if args is None:
# args default to the system args
args = _sys.argv[1:]
else:
# make sure that args are mutable
args = list(args)
# default Namespace built from parser defaults
if namespace is None:
# add any action defaults that aren't present
for action in self._actions:
if action.dest is not SUPPRESS:
if not hasattr(namespace, action.dest):
# add any parser defaults that aren't present
for dest in self._defaults:
if not hasattr(namespace, dest):
# parse the arguments and exit if there are any errors
if self.exit_on_error:
try:
> namespace, args = self._parse_
/usr/lib/
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = ArgumentParser(
arg_strings = ['-uNIDFeflx', 'machines', 'read']
namespace = Namespace(
def _parse_
# replace arg strings that are file references
if self.fromfile_
# map all mutually exclusive arguments to the other arguments
# they can't occur with
for mutex_group in self._mutually_
for i, mutex_action in enumerate(
# find all option indices, and determine the arg_string_pattern
# which has an 'O' if there is an option at an index,
# an 'A' if there is an argument, or a '-' if there is a '--'
for i, arg_string in enumerate(
# all args after -- are non-options
if arg_string == '--':
# otherwise, add the arg to the arg strings
# and note the index if it was an option
else:
if option_tuple is None:
# join the pieces together to form the pattern
# converts arg strings to the appropriate and then takes the action
def take_action(action, argument_strings, option_
# error if this argument is not allowed with other previously
# seen arguments, assuming that actions that use the default
# value don't really count as "present"
if argument_values is not action.default:
# take the action if we didn't receive a SUPPRESS value
# (e.g. from a default)
if argument_values is not SUPPRESS:
# function to convert arg_strings into an optional action
def consume_
# get the optional identified at this index
# identify additional optionals in the same arg string
# (e.g. -xyz is the same as -x -y -z if no args are required)
while True:
# if we found no optional action, skip it
if action is None:
# if there is an explicit argument, try to match the
# optional's string arguments to only this
if explicit_arg is not None:
# if there is no explicit argument, try to match the
# optional's string arguments with the following strings
# if successful, exit the loop
# add the Optional to the list and return the index at which
# the Optional's string args stopped
assert action_tuples
for action, args, option_string in action_tuples:
return stop
# the list of Positionals left to be parsed; this is modified
# by consume_
# function to convert arg_strings into positional actions
def consume_
# match as many Positionals as possible
# slice off the appropriate arg strings for each Positional
# and add the Positional and its args to the list
for action, arg_count in zip(positionals, arg_counts):
# slice off the Positionals that we just parsed and return the
# index at which the Positionals' string args stopped
return start_index
# consume Positionals and Optionals alternately, until we have
# passed the last option string
extras = []
if option_
else:
while start_index <= max_option_
# consume any Positionals preceding the next option
if index >= start_index])
if start_index != next_option_
# only try to parse the next optional if we didn't consume
# the option string during the positionals parsing
if positionals_
# if we consumed all the positionals we could and we're not
# at the index of an option string, there were extra arguments
if start_index not in option_
# consume the next optional and any arguments for it
# consume any positionals following the last Optional
> stop_index = consume_
/usr/lib/
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
start_index = 3
def consume_
# match as many Positionals as possible
arg_counts = match_partial(
# slice off the appropriate arg strings for each Positional
# and add the Positional and its args to the list
for action, arg_count in zip(positionals, arg_counts):
args = arg_strings[
> take_action(action, args)
/usr/lib/
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
action = _SubParsersActi
argument_strings = ['machines', 'read'], option_string = None
def take_action(action, argument_strings, option_
> argument_values = self._get_
/usr/lib/
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = ArgumentParser(
action = _SubParsersActi
arg_strings = ['machines', 'read']
def _get_values(self, action, arg_strings):
# for everything but PARSER, REMAINDER args, strip out first '--'
if action.nargs not in [PARSER, REMAINDER]:
try:
except ValueError:
# optional argument produces a default when not present
if not arg_strings and action.nargs == OPTIONAL:
if action.
else:
if isinstance(value, str):
# when nargs='*' on a positional, if there were no command-line
# args, use the default if it is anything other than None
elif (not arg_strings and action.nargs == ZERO_OR_MORE and
not action.
if action.default is not None:
else:
# single argument or optional argument produces a single value
elif len(arg_strings) == 1 and action.nargs in [None, OPTIONAL]:
value = self._get_
# REMAINDER arguments convert all values, checking none
elif action.nargs == REMAINDER:
value = [self._
# PARSER arguments convert all values, but check only the first
elif action.nargs == PARSER:
value = [self._
> self._check_
/usr/lib/
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = ArgumentParser(
action = _SubParsersActi
value = 'machines'
def _check_value(self, action, value):
# converted value must be one of the choices (if specified)
if action.choices is not None and value not in action.choices:
args = {'value': value,
msg = _('invalid choice: %(value)r (choose from %(choices)s)')
> raise ArgumentError(
E argparse.
/usr/lib/
During handling of the above exception, another exception occurred:
perf = <maastesting.
cli_profile = {'credentials': ['vDF3XGWUnRUVV
monkeypatch = <_pytest.
cli_machines_
@pytest.
def test_perf_
perf, cli_profile, monkeypatch, cli_machines_
):
def mock_ProfileCon
yield {cli_profile[
def mock_http_
return (
),
)
args = ["maas", cli_profile[
with perf.record(
parser = prepare_
with perf.record(
> options = parser.
src/tests/
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib/
args, argv = self.parse_
/usr/lib/
self.
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = ArgumentParser(
message = "argument COMMAND: invalid choice: 'machines' (choose from 'login', 'logout', 'list', 'refresh', 'init', 'apikey', 'configauth', 'config-tls', 'config-vault', 'createadmin', 'changepassword', '-uNIDFeflx')"
def error(self, message):
"""Make the default error messages more helpful
Override default ArgumentParser error method to print the help menu
generated by ArgumentParser instead of just printing out a list of
valid arguments.
"""
> sys.exit(2)
E SystemExit: 2
src/maascli/
------
Operations to perform:
Apply all migrations: auth, contenttypes, maasserver, metadataserver, piston3, sessions, sites
Running migrations:
No migrations to apply.
------
usage: maas [-h] COMMAND ...
options:
-h, --help show this help message and exit
drill down:
COMMAND
login Log in to a remote API, and remember its description and
logout Log out of a remote API, purging any stored credentials.
list List remote APIs that have been logged-in to.
refresh Refresh the API descriptions of all profiles.
init Initialize controller.
apikey Used to manage a user's API keys. Shows existing keys unless
configauth Configure external authentication.
config-tls Configure MAAS Region TLS.
config-vault Configure MAAS Region Vault integration.
createadmin Create a MAAS administrator account.
changepassword
-uNIDFeflx Interact with http://
argument COMMAND: invalid choice: 'machines' (choose from 'login', 'logout', 'list', 'refresh', 'init', 'apikey', 'configauth', 'config-tls', 'config-vault', 'createadmin', 'changepassword', '-uNIDFeflx')
Related branches
- MAAS Lander: Approve
- Alberto Donato (community): Approve
-
Diff: 13 lines (+1/-1)1 file modifiedsrc/tests/maasperf/cli/conftest.py (+1/-1)
Changed in maas: | |
assignee: | nobody → Adam Collard (adam-collard) |
Changed in maas: | |
status: | Triaged → Fix Committed |
Changed in maas: | |
milestone: | 3.4.0 → 3.4.0-beta3 |
Changed in maas: | |
status: | Fix Committed → Fix Released |