-
-
Notifications
You must be signed in to change notification settings - Fork 779
Make unit tests use redis #6245
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
Conversation
2697dea to
f2f1a62
Compare
This reverts commit 820001d.
All tests (unit, integration, pack) need redis now.
tests_config.parse_args is called when importing st2tests and again in setUpClass. if this is needed, try self.reset()
8c16324 to
f772e71
Compare
get_members should return a list or tuple, not a string. I noticed while debugging that get_members output ended up as ['m', 'e', 'm', 'b', 'e', 'r', '-', '1'] because it listified the string. So, use a tuple when creating the mocked NoOpAsyncResult so it is closer to the actual return values.
9f6f8d0 to
5cfd1ff
Compare
ab46c40 to
78c3248
Compare
| # This needs to run before creating FakeConcurrencyApplicator below. | ||
| tests_config.parse_args() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These tests were inadvertently using the NoOpDriver because of the import-time creation of FakeConcurrencyApplicator in the @mock.patch.object decorators. parse_args() wasn't called until setUpClass which happens after import time.
I found this by putting some raise ValueError in codepaths that create the NoOpDriver to make sure nothing was using it.
| tests_config.reset() | ||
| tests_config.parse_args() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since these tests need to control the config, changing values in each test, it makes more sense to setup the cfg.CONF per test instead of only during setUpClass. These two lines ensure that the config has been reset to a clean state before proceeding.
In a future refactor, this would be a good function to turn into a pytest fixture, after we've got pytest running everything.
| tests_config.reset() | ||
| tests_config.parse_args() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same issues with tests_config apply to this file too. So, reset it per test, not just per class.
| coordination.ToozConnectionError("foobar"), | ||
| coordination.ToozConnectionError("foobar"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without this, the side effect happens too much, resulting in this traceback + test error:
======================================================================
1) ERROR: test_process_error_handling (tests.unit.test_workflow_engine.WorkflowExecutionHandlerTest)
----------------------------------------------------------------------
Traceback (most recent call last):
virtualenv/lib/python3.8/site-packages/mock/mock.py line 1452 in patched
return func(*newargs, **newkeywargs)
st2actions/tests/unit/test_workflow_engine.py line 227 in test_process_error_handling
workflows.get_engine().process(t1_ac_ex_db)
st2actions/st2actions/workflows/workflows.py line 103 in process
self.fail_workflow_execution(message, e)
st2actions/st2actions/workflows/workflows.py line 191 in fail_workflow_execution
wf_svc.update_task_state(task_ex_id, ac_const.LIVEACTION_STATUS_FAILED)
virtualenv/lib/python3.8/site-packages/retrying.py line 56 in wrapped_f
return Retrying(*dargs, **dkw).call(f, *args, **kw)
virtualenv/lib/python3.8/site-packages/retrying.py line 257 in call
return attempt.get(self._wrap_exception)
virtualenv/lib/python3.8/site-packages/retrying.py line 301 in get
six.reraise(self.value[0], self.value[1], self.value[2])
virtualenv/lib/python3.8/site-packages/six.py line 719 in reraise
raise value
virtualenv/lib/python3.8/site-packages/retrying.py line 251 in call
attempt = Attempt(fn(*args, **kwargs), attempt_number, False)
virtualenv/lib/python3.8/site-packages/retrying.py line 56 in wrapped_f
return Retrying(*dargs, **dkw).call(f, *args, **kw)
virtualenv/lib/python3.8/site-packages/retrying.py line 266 in call
raise attempt.get()
virtualenv/lib/python3.8/site-packages/retrying.py line 301 in get
six.reraise(self.value[0], self.value[1], self.value[2])
virtualenv/lib/python3.8/site-packages/six.py line 719 in reraise
raise value
virtualenv/lib/python3.8/site-packages/retrying.py line 251 in call
attempt = Attempt(fn(*args, **kwargs), attempt_number, False)
st2common/st2common/services/workflows.py line 1054 in update_task_state
update_execution_records(
st2common/st2common/services/workflows.py line 1475 in update_execution_records
ex_svc.update_execution(wf_lv_ac_db, publish=pub_ac_ex, set_result_size=True)
st2common/st2common/services/executions.py line 199 in update_execution
with coordination.get_coordinator().get_lock(str(liveaction_db.id).encode()):
virtualenv/lib/python3.8/site-packages/mock/mock.py line 1178 in __call__
return _mock_self._mock_call(*args, **kwargs)
virtualenv/lib/python3.8/site-packages/mock/mock.py line 1182 in _mock_call
return _mock_self._execute_mock_call(*args, **kwargs)
virtualenv/lib/python3.8/site-packages/mock/mock.py line 1243 in _execute_mock_call
raise result
ToozConnectionError: foobar
| "update_task_state", | ||
| mock.MagicMock( | ||
| side_effect=[ | ||
| mongoengine.connection.ConnectionFailure(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without this, the side effect happens too much, resulting in this traceback + test error on at least python3.9 (and probably newer):
======================================================================
1) ERROR: test_recover_from_database_connection_error (tests.unit.services.test_workflow_service_retries.OrquestaServiceRetryTest)
----------------------------------------------------------------------
Traceback (most recent call last):
virtualenv/lib/python3.9/site-packages/mock/mock.py line 1452 in patched
return func(*newargs, **newkeywargs)
st2common/tests/unit/services/test_workflow_service_retries.py line 222 in test_recover_from_database_connection_error
wf_svc.handle_action_execution_completion(tk1_ac_ex_db)
virtualenv/lib/python3.9/site-packages/retrying.py line 56 in wrapped_f
return Retrying(*dargs, **dkw).call(f, *args, **kw)
virtualenv/lib/python3.9/site-packages/retrying.py line 266 in call
raise attempt.get()
virtualenv/lib/python3.9/site-packages/retrying.py line 301 in get
six.reraise(self.value[0], self.value[1], self.value[2])
virtualenv/lib/python3.9/site-packages/six.py line 719 in reraise
raise value
virtualenv/lib/python3.9/site-packages/retrying.py line 251 in call
attempt = Attempt(fn(*args, **kwargs), attempt_number, False)
st2common/st2common/services/workflows.py line 969 in handle_action_execution_completion
update_task_state(
virtualenv/lib/python3.9/site-packages/mock/mock.py line 1178 in __call__
return _mock_self._mock_call(*args, **kwargs)
virtualenv/lib/python3.9/site-packages/mock/mock.py line 1182 in _mock_call
return _mock_self._execute_mock_call(*args, **kwargs)
virtualenv/lib/python3.9/site-packages/mock/mock.py line 1243 in _execute_mock_call
raise result
ConnectionFailure:
| redis_host = os.environ.get("ST2TESTS_REDIS_HOST", False) | ||
| if redis_host: | ||
| redis_port = os.environ.get("ST2TESTS_REDIS_PORT", "6379") | ||
| driver = f"redis://{redis_host}:{redis_port}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ST2TESTS_* is the convention I've been using for vars that configure tests:
st2/st2tests/st2tests/config.py
Lines 89 to 90 in 78c3248
| db_name = f"st2-test{os.environ.get('ST2TESTS_PARALLEL_SLOT', '')}" | |
| CONF.set_override(name="db_name", override=db_name, group="database") |
st2/st2tests/st2tests/config.py
Lines 107 to 109 in 78c3248
| system_user = os.environ.get("ST2TESTS_SYSTEM_USER", "") | |
| if system_user: | |
| CONF.set_override(name="user", override=system_user, group="system_user") |
| - name: Run Redis Service Container | ||
| timeout-minutes: 2 | ||
| run: | | ||
| docker run --rm --detach -p 127.0.0.1:6379:6379/tcp --name redis redis:latest | ||
| until [ "$(docker inspect -f {{.State.Running}} redis)" == "true" ]; do sleep 0.1; done |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We only need one redis container, either started here or in services above. The services approach is a bit nicer because we know that redis is up and responding (thanks to the health check that GHA waits for before continuing), whereas this just makes ssure the container (not redis in the container) is running.
This was also the cause of the conflicts where redis was already in use. Getting rid of this allows us to use the simple redis name for the service container instead of redis-server.
|
The Luckily, the pants workflows are not required to merge PRs (in branch protection rules), so please ignore the failure. |
|
Thanks for going through this. The noop driver random failures were a pain to deal with. |
nzlosh
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, this is great work!
This makes the orquesta workflow consistent with ci workflow changes added in #6245
This makes the orquesta workflow consistent with ci workflow changes added in #6245
This makes the orquesta workflow consistent with ci workflow changes added in #6245
The graceful_shutdown tests have been very flaky using the
NoOpDriver. Switching fromNoOpDrivertoRedisDriverwill hopefully make our CI more stable.This was discussed in a TSC meeting and implemented by @FileMagic (#6223) and @guzzijones (#6236). I cherry-picked the redis-related parts of their excellent work. After stumbling through the cherry-picks (I missed a few things, and had to rebase/cherry-pick a few times), I refactored a few things:
rediscontainer defined inservices, dropping the tasks that managed it manually.ST2TESTS_REDIS_*as the format for new env vars instead ofST2_OVERRIDE_COORDINATOR_REDIS_*.👏 Thank you @FileMagic and @guzzijones for getting this figured out! I have high hopes for more stable CI thanks to your excellent work! 🎉