Add integration test for power_state_change module#717
Conversation
| @@ -0,0 +1,13 @@ | |||
| def ordered_items_in_text(to_verify: list, text: str): | |||
There was a problem hiding this comment.
log_utils.py is better than utils.py, right???
But in all seriousness, I'm open to suggestions of a better place to put something like this.
OddBloke
left a comment
There was a problem hiding this comment.
Thanks James! The test itself LGTM, with a few minor nits/comments; the framework changes, however, I think may not be correct.
| @@ -0,0 +1,13 @@ | |||
| def ordered_items_in_text(to_verify: list, text: str): | |||
There was a problem hiding this comment.
| def ordered_items_in_text(to_verify: list, text: str): | |
| def ordered_items_in_text(to_verify: list, text: str) -> bool: |
There was a problem hiding this comment.
(And I suppose s/list/Iterable[str]/ but let's not import typing just for that. ;))
| def running(self): | ||
| # TODO: Implement something better in pycloudlib | ||
| try: | ||
| return True if self.execute('true').return_code == 0 else False |
There was a problem hiding this comment.
| return True if self.execute('true').return_code == 0 else False | |
| return self.execute('true').ok |
There was a problem hiding this comment.
Bah! True if ... else False is a code peeve of mine and I just committed it! (but yes, I'll update this 😉 )
| with session_cloud.launch( | ||
| user_data=USER_DATA.format( | ||
| delay=delay, mode=mode, timeout=timeout, condition='true'), | ||
| launch_kwargs={'wait': False}, |
There was a problem hiding this comment.
This feels a bit like a conflation. We universally opt out of pycloudlib's default waiting behaviour (i.e. launch(..., wait=False, ...)) and implement our own. I believe that what we're configuring here is that we don't want our waiting behaviour to apply (in addition to the invariant of pycloudlib's waiting not applying). As launch_kwargs is used to pass kwargs to pycloudlib's launch method, it feels wrong to be using it to carry configuration which, by design, will never be passed through to launch.
Given that we are actually configuring our launch method to not wait here, should this instead be a wait=True kwarg on session_cloud.launch?
| # detecting the first boot or second boot, so we also check | ||
| # the logs to ensure we've booted twice. If the logs show we've | ||
| # only booted once, wait until we've booted twice | ||
| instance.instance.wait() |
There was a problem hiding this comment.
Should we be passing raise_on_cloudinit_failure=False here?
| ]) | ||
| def test_poweroff(self, session_cloud: IntegrationCloud, | ||
| mode, delay, timeout, expected): | ||
| with session_cloud.launch( |
There was a problem hiding this comment.
This is a nice example of the flexibility of the framework we have; good job!
| assert instance.running | ||
| lines_to_check = [ | ||
| 'Running module power-state-change', | ||
| expected.format(delay=delay), |
There was a problem hiding this comment.
Looks like all of the values expected can take are straight-up strings, so I think we can drop the .format here?
| from tests.integration_tests.log_utils import ordered_items_in_text | ||
| import pytest | ||
| import time | ||
|
|
||
| from tests.integration_tests.clouds import IntegrationCloud | ||
| from tests.integration_tests.instances import IntegrationInstance |
There was a problem hiding this comment.
https://www.python.org/dev/peps/pep-0008/#imports 🏃 💨
(A nit.)
| return image.image_id | ||
|
|
||
| def _perform_launch(self, launch_kwargs): | ||
| wait = launch_kwargs.pop('wait', True) |
There was a problem hiding this comment.
If wait isn't in launch_kwargs then it will default to True, meaning that cloud-init failures will raise an exception. (More on this issue further down.)
|
This isn't running successfully for me locally; I've seen this a few times (but not every time): But also: (That assert could probably use a message, if you can figure out a good one to emit.) |
(Other than this, the code LGTM now, thanks!) |
(Let me know if there's anything I can do to help debug!) |
8b85251 to
3a2e147
Compare
|
@OddBloke I don't think it's worth investing anymore time in this test at this point. I get different weird errors (or just bugs in pycloudlib and lxd) from different clouds, and it's not worth the time fixing them now. I can either remove the test and run things manually, or keep the test around knowing its flaky and remove it from the normal test runs. I think there is value in keeping the test (hence my last commit), but I also understand not wanting to dirty our test base with flaky tests, so I'd be ok removing it too. What are your thoughts? |
| supported_os_set = set(os_list).intersection(test_marks) | ||
| if current_os and supported_os_set and current_os not in supported_os_set: | ||
| pytest.skip("Cannot run on OS {}".format(current_os)) | ||
| if 'unstable' in test_marks: |
There was a problem hiding this comment.
Is it worth adding RUN_UNSTABLE as a setting, so the interface for forcing a run is CLOUD_INIT_RUN_UNSTABLE=true rather than a code modification?
| # This test is marked unstable because even though it should be able to | ||
| # run anywhere, I can only get it to run in an lxd container, and even then | ||
| # occasionally some timing issues will crop up. | ||
| @pytest.mark.unstable |
There was a problem hiding this comment.
It might be nice to have a timed element like we have in the curtin tests: unstable_until("2021/02/01") to force us to fix it at some point. Not needed for now, though.
OddBloke
left a comment
There was a problem hiding this comment.
LGTM, thanks! Ideally we'd have a stable test here, but pragmatically we're better landing this (which we know is inert by default, and useful enough for SRU verification) and moving forward.
Proposed Commit Message
Add integration test for power_state_change module
Additional Context
Based on #567 , but not naming the test after it because the changes that affected Ubuntu were only a refactor.
In the test, I've included adding a timeout to the user_data, but I don't know of a way to actually test it because the power state module is the last module to run, so even with a timeout of 1, cloud-init finishes before the timeout is triggered.
Test Steps
pytest tests/integration_tests/modules/test_power_state_change.py
Checklist: