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
tests(refactor): Adjust mail_changedetector
+ change detection helpers
#2997
tests(refactor): Adjust mail_changedetector
+ change detection helpers
#2997
Conversation
|
||
repeat_until_success_or_timeout 60 __is_changedetector_finished | ||
repeat_until_success_or_timeout 20 __has_expected_count |
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.
I haven't compared, but casper had suggested a different approach than polling like I'm doing here.
repeat_until_success_or_timeout 20 __has_expected_count | |
timeout 60 docker exec "${CONTAINER_NAME}" bash -c "tail -F '${MATCH_IN_LOG}' | grep --max-count ${EXPECTED_COUNT} '${MATCH_CONTENT}'" |
That will take a stream of the log and exit once the result count is matched. It needed to use bash -c
, even if using docker logs --follow
for the input as I found it'd hang otherwise (presumably something to do with stdin not closing?)
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.
I cannot reproduce the hanging. I tried this:
# exit as soon as the keyword "spawned" appears
docker logs -n0 -f mail | grep -q spawned
Then in another session:
docker exec mail supervisorctl restart update-check
PS: The container must be running with SUPERVISOR_LOGLEVEL=info
I think, that this example works.
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
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.
I was able to reproduce on current master the same issue. I tested with replacing this:
docker-mailserver/test/tests/parallel/set1/spam_virus/spam_junk_folder.bats
Lines 33 to 35 in 1650cdf
# message will be added to a queue with varying delay until amavis receives it | |
run repeat_until_success_or_timeout 60 bash -c "docker logs ${CONTAINER_NAME} | grep 'Passed SPAM {RelayedTaggedInbound,Quarantined}'" | |
assert_success |
Reproduction
# Passes before timing out:
timeout 20 docker exec "${CONTAINER_NAME}" bash -c "tail -F /var/log/mail/mail.log | grep --max-count 1 'Passed SPAM'"
# Same result here:
docker exec "${CONTAINER_NAME}" bash -c "timeout 20 tail -F /var/log/mail/mail.log | grep --max-count 1 'Passed SPAM'"
# Times out with failure, and due to -q has no output:
timeout 20 bash -c "docker logs --follow ${CONTAINER_NAME} | grep -q 'Passed SPAM'"
# Times out with failure, but correctly shows output of requested max lines (even if there were more present)
timeout 20 bash -c "docker logs --follow ${CONTAINER_NAME} | grep --max-count 1 'Passed SPAM'"
# Times out but **passes** (docker logs was stopped by timeout, grep was successful)
timeout 20 docker logs --follow "${CONTAINER_NAME}" | grep --max-count 1 'Passed SPAM'
function _passed_spam() {
# Any method from above here
}
# Replace as 2nd assert in either test case of `tests/parallel/set1/spam_virus/spam_junk_folder.bats:
run _passed_spam
assert_success
Perhaps it's something different with our environments or how docker logs --follow
works on our machines? For me, given the above observations, it doesn't seem like the stream is closed?
I had also verified by running the same command in another terminal session directly while the test was running. It would find the match and output it, but not exit until the timeout was reached.
I've had a similar experience with -q
(not as nice as --max-count
), where either option was working at least for decoder
as the value to match when the container was starting up (I could not reproduce with Passed SPAM
for some reason..). I could repeat the command in the terminal several times and it'll exit quickly with either option successful. However a few seconds after that and it would fail, even though the logs command would clearly show the lines 🤷♂️
Clearly something is iffy there, at least on my end :\
UPDATE: My grep
command is the problem.
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.
I swapped grep
for rg
(ripgrep), and now it works as you'd expect...
So something wrong with my grep
command I guess? 🤷♂️
I'd rather avoid the -q
or --max-count
approach, at least with a local grep call, as it seems that's where the problem is. The containers grep was working fine with tail
, which would be ok as it avoids false positives when I run tests locally.
We could add ripgrep
as a dependency for testing like we do with jq
I suppose? (but then CI may need to grab/install it each time, unless it already provides that like it does jq
)
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.
So something wrong with my grep command I guess? 🤷♂️
yes 😄
docker logs ${CONTAINER_NAME} | grep 'Passed SPAM {RelayedTaggedInbound,Quarantined}'"
When you don't pass -q
or --max-count 1
, grep runs infinitly. Why should it stop?
If you only need to now, if a keyword was found, go with -q
. If you need the output to parse further or make assertions, go with --max-count 1
.
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.
When you don't pass
-q
or--max-count 1
, grep runs infinitly. Why should it stop?
You're referring to the current version in master I referenced? That is not using --follow
, so it does not run infinitely. The attempts I tried can be found in the collapsed "> Reproduction" section.
I collapsed it after responding with an update about my local grep
being the problem. I understand the reason for -q
or --max-count 1
, but only if we're using grep
within the container (doesn't make sense for docker logs --follow
due to that), as for whatever reason my local grep
is misbehaving which would be problematic for me running tests locally 😅 (something I've been doing quite frequently lately)
If we're to use either option with docker logs --follow
, then I'd need to know why my grep
is broken and how to fix it, or add ripgrep
as a dependency for tests.
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 attempts I tried can be found in the collapsed "> Reproduction" section.
Thanks, I overlooked that.
BTW: Are you running the tests on debian/ubuntu?
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.
Are you running the tests on debian/ubuntu?
EndeavourOS (ArchLinux based)
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.
Depending on how much more time you want to invest, you may try the "grep" binary from debian:
docker create --name grep debian
docker cp grep:/bin/grep .
docker rm grep
I am wondering, that such a basic tool behaves differently between linux distros.
PS: If we are ever in doubt, we should stick with debian based distros supported for testing (because CI is also running on ubuntu).
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.
Looks really good to me! Just some very minor stylistic changes :)
Got an upcoming PR about changes to UPDATE: branch pushed, name = |
I see you've got a nice clean separation of commits so that's fine if you want to bundle If you're planning to rework more tests into that branch, maybe use a separate branch for the broader change with renaming; then after that's merged cherry-pick the extra commits into a new branch / PR? 😅 I'm not bothered either way, but it is preferable to separate out diff noise (like the method renaming interfering with a different scope of changes) from the "review changes" view when possible :) Small heads-up, there will be some conflicts for either you or me to deal with as I'm presently putting together a test file that collects all the process checking and restarts into a single file. That affects some of the tests your function rename touches as it deletes the test cases from those parallel set tests. It affects the following tests presently:
It may also remove the need for |
test/helper/common.bash
Outdated
if [[ -z $EXPECTED_COUNT ]] | ||
then | ||
# +1 of starting count: | ||
EXPECTED_COUNT=$(bc <<< "$(__get_count) + 1") |
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.
EXPECTED_COUNT=$(bc <<< "$(__get_count) + 1") | |
EXPECTED_COUNT=$(( $(__get_count) + 1 )) |
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.
Oh weird, I remember having trouble getting that to work at the time and had ended up with the bc <<<
version 😅
That works well, thanks! 😁
EDIT: Broke smtp-delivery.bats
where an implicit count is used.
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.
No glue why this doesn't work and the tests fail 🤷
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.
Alright, I found the root cause.
Because, set -e
is in use, the $(())
operation fails, because the called function __get_count
returns exit code 1, when there are 0 matches.
As 0 matches is a valid return value (for us), this should be fixed by appending || true
:
docker exec "${CONTAINER_NAME}" grep --count "${MATCH_CONTENT}" "${MATCH_IN_LOG}" || true
.
After that, EXPECTED_COUNT=$(( $(__get_count) + 1 ))
works fine.
I'll be resolving the conflicts, don't worry! I'll be using a train ride tomorrow, so I hope we can merge this until tomorrow evening - that'd be nice :D |
There was a failure related to the change detection wait method in parallel set3 |
Confirmed. The The change @casperklein proposed caused instant failure during |
`supervisorctl tail` is not the most reliably way to get logs for the latest change detection and has been known to be fragile in the past. We can instead read the full log for the service directly with `tac` and `sed` to extract all log content since the last change detection. Common asserts have also been extracted out into separate methods.
Container 1 is still blocked at this point from an existing lock and change event. Make the lock stale immediately and no extra sleep is required when paired with the helper method to wait until the event is processed (which should remove the stale lock).
- Simplify the test case so it's easier to grok. - 2nd test case (blocking) extracts out initial setup into a separate method and merges the later service restart logic which is redundant. - Additional comments for improved context of what is going on / expected.
- Add explicit counting arg to change detection support. - Extract revised logic into it's own generic helper method. - Utilize this for a separate method that monitors for a change event having started, but not waiting for completion. This allows dropping the 40 sec of remaining `sleep` in `mail_changedetector` test. It was also required due to potentially missing the timing of a change event completing concurrently in a 2nd container that needed to be waited on and then checked.
- Switch to common container setup helpers - Update container name and change usage to variables instead. - Adopt the new convention of prefix variable for test cases (revised test case descriptions).
This test file was already adapted to the original common setup helpers. - `TEST_NAME` replaced with `CONTAINER_NAME`. - Prefix var added, test case descriptions drop explicit prefix. - No other changes.
- New helper file for sharing these helpers to tests. - Includes the helpful log method from changedetector tests. - No longer need to maintain duplicate copies of these methods during the test migration. All tests that use them are now importing the separate helper file. - `tls_letsencrypt.bats` has switched to using the log helper. - Generic log count helper is removed from `test_helper/common.bash` as any test that needs it in future can adapt to `helper/common.bash`.
This helper does not seem useful as moving away from `supervisorctl tail` and no other tests had a need for it.
No other tests depend on this. Future tests will adopt the revised versions from `helper/setup.bash`. Additionally updates `helper/setup.bash` comments that are no longer applicable to `TEST_TMP_CONFIG` and `CONTAINER_NAME`.
Review feedback Co-authored-by: Georg Lauterbach <44545919+georglauterbach@users.noreply.github.com>
Review feedback request
Co-authored-by: Casper <casperklein@users.noreply.github.com>
This reverts commit ed8078b.
76aea88
to
655bb50
Compare
Can be merged. I'll be placing a new PR then for the refactored helper ;) |
How to run only the set3 tests? This doesn't work:
Edit: For now, I use |
Did you run |
I did run just "make" to create all necessary stuff. Then tests failed and I wanted to re-run only set3. Same with your example:
|
I will have a look later at this too. |
Tested it again; runs smoothly on my system (Ubuntu 22.04 LTS). Packages are up-to-date. EDIT: Does |
yes |
Ok, missed my opportunity to merge with both approvals it seems 😛 I've added the solution @casperklein requested, hope this is good for merging now 👍 |
Description
mail_changedetector
to the new test conventions. Logic remains roughly the same, just easier to grok.tls_letsencrypt
test had some improvements as a result of this.setup-cli
test used the original setup helper methods, no change to logic there, just fully adapted tohelper/setup.bash
and adjusted the test case prefix.mail_changedetector
test as two concurrent change events happening, where one may have already processed before you can wait on it. Another test case cannot wait on completion, but instead needs to wait on a change detection starting.helper/common.bash
methods. This also allowed for dropping the helpers fromtest_helper/common.bash
, as well as the related methods in that file that now exist inhelper/setup.bash
.tests.bats
). Thus I've removed that method and the relatedtest_helper.bats
cases for it. Existing methods should have fairly decent coverage inmail_changedetector
using it against the actualchangedetector
service, and not just watching for a checksum change separately (which is not that useful for us).This refactor removes the need to depend on
sleep
, shaving off approx 2 mins of time (potentially a bit less until some additional PRs are merged).I've staged out changes across commits (with associated commit messages) that should make the review of diffs a bit more easier if it helps 😅
The original
mail_changedetector
test was implemented in Sep 2021. It was added with a focus on testing the locking script with multiple containers sharing a network volume for config (/tmp/docker-mailserver
).I have taken extra care with the changes done here (over several days). I ran repeat test runs, along with some other changes I'm pushing as separate PRs to ensure that the change detection tests remain consistent / reliable.
I was quite thorough with the refactor (easier to follow through the staged commit diffs). I am confident in it and the revised change detection helper.
Type of change
Checklist: