Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make end2end tests run against a mocked environment #413

Open
andy-maier opened this issue May 14, 2023 · 2 comments
Open

Make end2end tests run against a mocked environment #413

andy-maier opened this issue May 14, 2023 · 2 comments

Comments

@andy-maier
Copy link
Member

With PR #411 , the following error is surfaced (using a locally defined mock file, on Python 3.9 on macOS):

$ TESTHMC=mocked_z13_dpm make end2end
find . -type d -name 'htmlcov.end2end' | xargs -n 1 rm -rf
bash -c "TESTEND2END_LOAD=true py.test --color=yes  -v -s tests/end2end --cov zhmccli --cov-config .coveragerc.end2end --cov-report=html "
================================================================================= test session starts ==================================================================================
platform darwin -- Python 3.9.16, pytest-7.3.1, pluggy-1.0.0 -- /Users/maiera/virtualenvs/zhmccli39/bin/python
cachedir: .pytest_cache
rootdir: /Users/maiera/Projects/zhmcclient/repos/zhmccli
plugins: cov-4.0.0
collected 1 item                                                                                                                                                                       

tests/end2end/test_session.py::test_session_success[hmc_definition=mocked_z13_dpm] FAILED/Users/maiera/virtualenvs/zhmccli39/lib/python3.9/site-packages/coverage/control.py:801: CoverageWarning: No data was collected. (no-data-collected)
  self._warn("No data was collected.", slug="no-data-collected")


======================================================================================= FAILURES =======================================================================================
_________________________________________________________________ test_session_success[hmc_definition=mocked_z13_dpm] __________________________________________________________________

hmc_definition = HMCDefinition(nickname='mocked_z13_dpm', description='Mocked z13 in DPM mode', contact='', access_via='', mock_file='/...y_cert=True, cpcs=OrderedDict([('CPC1', OrderedDict([('machine_type', '2964'), ('dpm_enabled', True)]))]), add_vars={})

    def test_session_success(hmc_definition):  # noqa: F811
        # pylint: disable=redefined-outer-name
        """
        Test successful creation and deletion of an HMC session.
        """
    
        # Create the session
    
        # Set to True to debug 'zhmc session create'
        pdb = False
    
        zhmc_args = zhmc_session_args(hmc_definition) + ['session', 'create']
    
        # The code to be tested
>       rc, stdout, stderr = run_zhmc(zhmc_args, pdb=pdb)

tests/end2end/test_session.py:48: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
tests/end2end/utils.py:103: in run_zhmc
    proc = subprocess.Popen(p_args, env=env, **kwargs)
/usr/local/Cellar/python@3.9/3.9.16/Frameworks/Python.framework/Versions/3.9/lib/python3.9/subprocess.py:951: in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <Popen: returncode: None args: ['zhmc', '-h', None, '-u', 'None', '-p', 'Non...>, args = ['zhmc', '-h', None, '-u', 'None', '-p', ...], executable = b'zhmc', preexec_fn = None
close_fds = True, pass_fds = (), cwd = None, env = None, startupinfo = None, creationflags = 0, shell = False, p2cread = -1, p2cwrite = -1, c2pread = 5, c2pwrite = 6, errread = 7
errwrite = 8, restore_signals = True, gid = None, gids = None, uid = None, umask = -1, start_new_session = False

    def _execute_child(self, args, executable, preexec_fn, close_fds,
                       pass_fds, cwd, env,
                       startupinfo, creationflags, shell,
                       p2cread, p2cwrite,
                       c2pread, c2pwrite,
                       errread, errwrite,
                       restore_signals,
                       gid, gids, uid, umask,
                       start_new_session):
        """Execute program (POSIX version)"""
    
        if isinstance(args, (str, bytes)):
            args = [args]
        elif isinstance(args, os.PathLike):
            if shell:
                raise TypeError('path-like args is not allowed when '
                                'shell is true')
            args = [args]
        else:
            args = list(args)
    
        if shell:
            # On Android the default shell is at '/system/bin/sh'.
            unix_shell = ('/system/bin/sh' if
                      hasattr(sys, 'getandroidapilevel') else '/bin/sh')
            args = [unix_shell, "-c"] + args
            if executable:
                args[0] = executable
    
        if executable is None:
            executable = args[0]
    
        sys.audit("subprocess.Popen", executable, args, cwd, env)
    
        if (_USE_POSIX_SPAWN
                and os.path.dirname(executable)
                and preexec_fn is None
                and not close_fds
                and not pass_fds
                and cwd is None
                and (p2cread == -1 or p2cread > 2)
                and (c2pwrite == -1 or c2pwrite > 2)
                and (errwrite == -1 or errwrite > 2)
                and not start_new_session
                and gid is None
                and gids is None
                and uid is None
                and umask < 0):
            self._posix_spawn(args, executable, env, restore_signals,
                              p2cread, p2cwrite,
                              c2pread, c2pwrite,
                              errread, errwrite)
            return
    
        orig_executable = executable
    
        # For transferring possible exec failure from child to parent.
        # Data format: "exception name:hex errno:description"
        # Pickle is not used; it is complex and involves memory allocation.
        errpipe_read, errpipe_write = os.pipe()
        # errpipe_write must not be in the standard io 0, 1, or 2 fd range.
        low_fds_to_close = []
        while errpipe_write < 3:
            low_fds_to_close.append(errpipe_write)
            errpipe_write = os.dup(errpipe_write)
        for low_fd in low_fds_to_close:
            os.close(low_fd)
        try:
            try:
                # We must avoid complex work that could involve
                # malloc or free in the child process to avoid
                # potential deadlocks, thus we do all this here.
                # and pass it to fork_exec()
    
                if env is not None:
                    env_list = []
                    for k, v in env.items():
                        k = os.fsencode(k)
                        if b'=' in k:
                            raise ValueError("illegal environment variable name")
                        env_list.append(k + b'=' + os.fsencode(v))
                else:
                    env_list = None  # Use execv instead of execve.
                executable = os.fsencode(executable)
                if os.path.dirname(executable):
                    executable_list = (executable,)
                else:
                    # This matches the behavior of os._execvpe().
                    executable_list = tuple(
                        os.path.join(os.fsencode(dir), executable)
                        for dir in os.get_exec_path(env))
                fds_to_keep = set(pass_fds)
                fds_to_keep.add(errpipe_write)
>               self.pid = _posixsubprocess.fork_exec(
                        args, executable_list,
                        close_fds, tuple(sorted(map(int, fds_to_keep))),
                        cwd, env_list,
                        p2cread, p2cwrite, c2pread, c2pwrite,
                        errread, errwrite,
                        errpipe_read, errpipe_write,
                        restore_signals, start_new_session,
                        gid, gids, uid, umask,
                        preexec_fn)
E                       TypeError: expected str, bytes or os.PathLike object, not NoneType

/usr/local/Cellar/python@3.9/3.9.16/Frameworks/Python.framework/Versions/3.9/lib/python3.9/subprocess.py:1754: TypeError

---------- coverage: platform darwin, python 3.9.16-final-0 ----------
Coverage HTML written to dir htmlcov.end2end

=============================================================================== short test summary info ================================================================================
FAILED tests/end2end/test_session.py::test_session_success[hmc_definition=mocked_z13_dpm] - TypeError: expected str, bytes or os.PathLike object, not NoneType
================================================================================== 1 failed in 2.12s ===================================================================================
make: *** [end2end] Error 1

@andy-maier
Copy link
Member Author

andy-maier commented Feb 11, 2024

Initial analysis shows that create_hmc_session() only supports real HMCs, because it dos not create FakedSession objects for mocked HMCs.
See zhmcclient fixture hmc_session() for how it is done.

However, since delete_hmc_session() and is_valid_hmc_session() depend on working session IDs, we first need to add proper session ID support to the zhmcclient_mock support. Created zhmcclient/python-zhmcclient#1437 for that.

@andy-maier andy-maier modified the milestones: 1.10.0, 1.11.0 Feb 11, 2024
andy-maier added a commit to zhmcclient/python-zhmcclient that referenced this issue Mar 9, 2024
Note: Removal of session IDs in the mocked Logoff operation and validation
      of session IDs in any mocked operations that require to be logged on
      has not been implemented in this change. That would require passing
      the HTTP header fields to the mock support, which is not the case today
      and would require larger changes.

      However, since addition/removal/validation of session IDs is implemented
      for the FakedHmc class, this should be sufficient to provide the session
      ID support required for zhmcclient/zhmccli#413.

Details:

* Added support for dynamically creating a session ID in the
  mocked Logon operation (i.e. _urihandler.SessionsHandler).

* The new session ID is stored in the zhmcclient_mock.FakedHmc
  object in new support for adding, removing and validating
  session IDs.

* Added unit test cases for the session ID support in the
  zhmcclient_mock.FakedHmc class.

Signed-off-by: Andreas Maier <maiera@de.ibm.com>
andy-maier added a commit to zhmcclient/python-zhmcclient that referenced this issue Mar 11, 2024
Note: Removal of session IDs in the mocked Logoff operation and validation
      of session IDs in any mocked operations that require to be logged on
      has not been implemented in this change. That would require passing
      the HTTP header fields to the mock support, which is not the case today
      and would require larger changes.

      However, since addition/removal/validation of session IDs is implemented
      for the FakedHmc class, this should be sufficient to provide the session
      ID support required for zhmcclient/zhmccli#413.

Details:

* Added support for dynamically creating a session ID in the
  mocked Logon operation (i.e. _urihandler.SessionsHandler).

* The new session ID is stored in the zhmcclient_mock.FakedHmc
  object in new support for adding, removing and validating
  session IDs.

* Added unit test cases for the session ID support in the
  zhmcclient_mock.FakedHmc class.

Signed-off-by: Andreas Maier <maiera@de.ibm.com>
andy-maier added a commit to zhmcclient/python-zhmcclient that referenced this issue Mar 12, 2024
Note: Removal of session IDs in the mocked Logoff operation and validation
      of session IDs in any mocked operations that require to be logged on
      has not been implemented in this change. That would require passing
      the HTTP header fields to the mock support, which is not the case today
      and would require larger changes.

      However, since addition/removal/validation of session IDs is implemented
      for the FakedHmc class, this should be sufficient to provide the session
      ID support required for zhmcclient/zhmccli#413.

Details:

* Added support for dynamically creating a session ID in the
  mocked Logon operation (i.e. _urihandler.SessionsHandler).

* The new session ID is stored in the zhmcclient_mock.FakedHmc
  object in new support for adding, removing and validating
  session IDs.

* Added unit test cases for the session ID support in the
  zhmcclient_mock.FakedHmc class.

Signed-off-by: Andreas Maier <maiera@de.ibm.com>
@andy-maier andy-maier added this to the 1.11.0 milestone Mar 12, 2024
@andy-maier
Copy link
Member Author

PR zhmcclient/python-zhmcclient#1456 targeted for zhmcclient 1.15.0 provides dynamically created session IDs, and the ability in the FakedHmc class to validate, add and remove session IDs. That should allow to resolve this issue here.

@andy-maier andy-maier modified the milestones: 1.12.0, 1.13.0 Sep 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant