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

tests/common/util: Implement UChild, an abstraction for std::process::Child, to return UChild from run_no_wait instead #4136

Merged
merged 5 commits into from
Dec 3, 2022

Conversation

Joining7943
Copy link
Contributor

@Joining7943 Joining7943 commented Nov 13, 2022

UChild provides:

  • convenience methods to assert the current or final state of the child process
  • other convenience methods for usual actions on the child process
  • reduce deadlock situations and provide safer piping into the child process stdin

Changes in UCommand:

  • We capture the output of the child process stdout and stderr in a temporary file per default instead of using Stdio::piped for stdout and stderr.
  • Provide a method stderr_to_stdout to redirect stderr to stdout

Note, that some tests needed to be adjusted to the new return value of UCommand::run_no_wait.

@Joining7943 Joining7943 mentioned this pull request Nov 13, 2022
@github-actions
Copy link

GNU testsuite comparison:

Congrats! The gnu test tests/misc/timeout is no longer failing!

Copy link
Member

@tertsdiepraam tertsdiepraam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent! Could you add or refactor some tests to show why it's better than the normal test library? If you're adding a new test, please also show an example of what it would need to look like without the TestRunner.

Some first observations:

  • The commands should probably still be a UCommand that you pass to the TestRunner so that we don't need to specify each possible option in the TestRunner struct, provide builder methods for them, etc.. The way you've written it now feels error prone, because we need to keep the implementation of TestRunner in sync with the implementation of tail itself.
  • I'd like a stronger distinction between a command and a command result, like what UCommand/CmdResult has. Functions like assert_stdout_matches should not be implemented on the runner.
  • In general, I would advise you to not make this TestRunner do too much. It's doing argument handling, setting up the fixtures, running and managing a process, and checking the output. That's a big burden to put on one struct. It seems to me that your focus should be in managing the child process, because we have acceptable abstractions in place for the other jobs (UCommand, AtPath, CmdResult). To take it to an extreme, maybe it's possible to include most of the functionality as just a wrapper around std::process::Child? All the stuff like getting the intermediate stdout, kill_asserted, assert_alive should fit in there. Other things, like stderr_to_stdout could actually be interesting for other utils, too, so that could go into UCommand.
  • It's unclear to me what run_cmd is for. Note that you can already call sh (or other commands) quite easily with test_scenario.ccmd("sh") and you get all the UCommand functionality.
  • I don't like how it uses things from tail. The FollowMode and Signum could just be supplied as strings, instead. tail::text seems to be unused altogether, not just on Windows.

tests/by-util/test_tail.rs Outdated Show resolved Hide resolved
tests/by-util/test_tail.rs Show resolved Hide resolved
tests/by-util/test_tail.rs Outdated Show resolved Hide resolved
@Joining7943
Copy link
Contributor Author

Thanks for your comments :)

Perhaps something I'm not sure if it's clear, the TestRunner never intends to or will replace UCommand, CmdResult etc. and it is delegating to them where it can. Sure, if you like to you can do all the stuff as usual with the TestRunner, although if you don't need stderr_to_stdout or handling and asserting child processes you're maybe better off with the procedure as usual.

The TestRunner provides stderr_to_stdout (also for the usual run), run_no_wait, run_cmd and the assertions around stderr_to_stdout and child processes, together with some convenience around setting up the arguments for the actual run. I hope this gives you a better idea of what the TestRunner provides and maybe answers some of your points.

If the stderr_to_stdout functionality is useful for others and goes into UCommand I'm happy to be able to remove or at least drastically reduce the handling around it in the TestRunner :)

The way you've written it now feels error prone, because we need to keep the implementation of TestRunner in sync with the implementation of tail itself.

I'm not sure which parts are error prone and need to be in sync with tail (maybe besides the two arguments you mentioned, although I think it's more like a feature than a bug).

It's unclear to me what run_cmd is for. Note that you can already call sh (or other commands) quite easily with test_scenario.ccmd("sh") and you get all the UCommand functionality.

That's something very useful that can be used in run_cmd.

I'd like a stronger distinction between a command and a command result, like what UCommand/CmdResult has.

I like that.

tail::text seems to be unused altogether, not just on Windows.

Yep, that's something I've overseen, text is used in the tests later (which currently aren't there) and then the windows comment fits again ;)

@tertsdiepraam
Copy link
Member

tertsdiepraam commented Nov 14, 2022

Perhaps something I'm not sure if it's clear, the TestRunner never intends to or will replace UCommand, CmdResult etc. and it is delegating to them where it can.

Yeah this was clear!

If the stderr_to_stdout functionality is useful for others and goes into UCommand I'm happy to be able to remove or at least drastically reduce the handling around it in the TestRunner :)

Yeah I can think of some cases where this might be useful. We've had trouble testing the interleaving of stdout and stderr for ls before. Having this in UCommand would be useful!

I'm not sure which parts are error prone and need to be in sync with tail (maybe besides the two arguments you mentioned, although I think it's more like a feature than a bug).

I was thinking about the arguments, specifically. For example, if I add a new argument and want to add it to the TestRunner. I have to

  1. add a field for it,
  2. add a setter method with some logic in it to turn it into a string for the command,
  3. make sure that it's used correctly in parse_args,
  4. make sure that it's reset in reset and
  5. add it to the Default impl.

That's a lot of things to do if the alternative is just using a slice of strings just like it's used on the command line. I could easily see people forgetting to add it to reset, for instance, leading to subtle bugs in the tests. This is why I strongly prefer to remove all argument handling from TestRunner and stick UCommand for that.

@Joining7943
Copy link
Contributor Author

Here's the basics for stderr_to_stdout in UCommand. I have tested it by trying a little bit around and it worked so far. I'm going to write some proper tests. Maybe you can give me a short feedback upfront?

@github-actions
Copy link

GNU testsuite comparison:

Congrats! The gnu test tests/misc/timeout is no longer failing!

Copy link
Member

@tertsdiepraam tertsdiepraam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is (as always) more difficult than I imagined :) I was only thinking about the run case, which is indeed easy, but run_no_wait is difficult. Maybe we can make this easier by changing the API.

Maybe something like this:

let file = tempfile::NamedTempFile::new().unwrap();
scene.ucmd().stdout_and_stderr(file.as_file()).run();

Now, the ownership stays of the file with the caller, but stdout and stderr still get interleaved.

Alternatively, we are already thinking about adding some abstraction over std::process::Child, so this could be the first step:

pub struct UChild {
    raw: std::process::Child,
    output: Option<tempfile::NamedFile>,
}

There would be only one run_no_wait method, which always returns a UChild. And then we can implement methods like output, kill, assert_alive, etc. on this struct. I do have to note that this would be a big change, because we'd need to refactor everything that uses run_no_wait (used 53 times).

But there's a big upside to this, namely that it allows us to do something we can't do now. We can't currently do UCommand -> Child -> CmdResult, but only UCommand -> CmdResult (via run). If we make UChild::wait return a CmdResult then we can do UCommand -> UChild -> CmdResult. And that also means that these two are identical, which is cool:

command.run();
command.run_no_wait().wait();

What do you think?

@Joining7943
Copy link
Contributor Author

I definitely like the abstraction :) Sounds really good. It's a big task, but on the long run I think too the outcome would be worth it.

To be honest I'm not really convinced of the first one. You have this cumbersome setup in the test cases and have to care about the tempfile where you actually only want the output. I'm not a big fan of this extra method, too (maybe there's also a nicer name), but the CapturedOutput can return this tempfile too, if this is something you need.

Alternatively passing something like CapturedOutput into stderr_to_stderr would be something I could live with.

@tertsdiepraam
Copy link
Member

tertsdiepraam commented Nov 14, 2022

It's a big task, but on the long run I think too the outcome would be worth it.

Yeah that's what I'm thinking too. 53 uses is is also not too bad and 34 of those uses are in test_tail.rs actually. Most tests don't use run_no_wait, but only run (or succeeds, fails).

Alternatively passing something like CapturedOutput into stderr_to_stderr would be something I could live with.

Something like this? (I'm renaming it to CombinedOutput, because that makes more sense with this particular usage)

let out = CombinedOutput::new();
scene.ucmd().stdout_and_stderr(&out).run();

I quite like this!

As a sidenote, I want to thank you for cooperating on splitting the other PR up. I think this now enables us to have super interesting discussions and I'm excited to see where all the ideas you have go!

@Joining7943
Copy link
Contributor Author

I like it, too. I'm looking forward to the discussions.

So, what's the plan, regarding the refactor and CombinedOutput? Do we both, CombinedOutput first and then the refactor... ?

@tertsdiepraam
Copy link
Member

Up to you! If you want to do the UChild (or another name) thing that'd be awesome, but if you want to start with just combined output that's cool too.

@Joining7943
Copy link
Contributor Author

The name is perfect. I'll figure something out, then.

@github-actions
Copy link

GNU testsuite comparison:

Congrats! The gnu test tests/misc/timeout is no longer failing!

@Joining7943
Copy link
Contributor Author

Here's a first implementation of UChild. I've also refactored 3 tests in test_tail so you have some usage examples and if you like to try around yourself. I hope the handling is intuitive, so far. I haven't started with stdout_and_stderr(CombinedOutput). I'm not exactly sure if we actually need it. Maybe you have some feedback before I start with refactoring all tests? I've also added some comments, documentation for orientation and some TODOs and FIXMEs. The deadlock situation described in the FIXME indeed happened with bigger output, so maybe we should fix this, too.

Copy link
Member

@tertsdiepraam tertsdiepraam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Liking this a lot already. The tests looks so clean! I have some suggestions about the API below.

I haven't started with stdout_and_stderr(CombinedOutput). I'm not exactly sure if we actually need it.

Yeah I don't think we need stdout_and_stderr(CombinedOutput) with this.

tests/common/util.rs Outdated Show resolved Hide resolved
tests/common/util.rs Show resolved Hide resolved
tests/common/util.rs Outdated Show resolved Hide resolved
tests/common/util.rs Outdated Show resolved Hide resolved
tests/common/util.rs Outdated Show resolved Hide resolved
@github-actions
Copy link

GNU testsuite comparison:

GNU test failed: tests/misc/tee. tests/misc/tee is passing on 'main'. Maybe you have to rebase?

@github-actions
Copy link

GNU testsuite comparison:

GNU test failed: tests/misc/timeout. tests/misc/timeout is passing on 'main'. Maybe you have to rebase?

@Joining7943
Copy link
Contributor Author

I've refactored all tests and util to use run_no_wait -> UChild. There are currently some errors happening during the tests I couldn't solve right away. Here's the background:

I've changed piping input to the child process' stdin happen in a separate thread (in run() and run_piped_stdin(), what's the majority of use cases, currently), so there should be no deadlocks situations anymore because of piping input into the child process within the actual main process. (UCommand::pipe_in together with plain UCommand::run_no_wait doesn't work this way, currently. I'm working on it to make this happen, but this is not too important, at the moment)

The changed piping changes the test situation a bit (I think to the better) and there are failures in test_tac and test_tee related to this change. I'm not familiar with the implementation of them, so I'm not sure, but my suspicions are:

  • test_tee: The failing tests look like they are supposed to fail because of a broken pipe. I'm not sure if they should use the UCommand::ignore_stdin_write_error() method or check for the error to happen.
  • test_tac: The tests fail randomly on windows when using UCommand::pipe_in. I suspect, that the reading from stdin in tac doesn't work properly, since UCommand doesn't block anymore until all stdin is fed into the child process. In a real world scenario piped input also comes from a separate process, so maybe there's something wrong with tac?

Are you familiar with tee and tac and have some feedback?

@tertsdiepraam
Copy link
Member

I can look more into it later, but have you tried with GNU tee and tac instead and do you get the same errors there?

@Joining7943
Copy link
Contributor Author

I can look more into it later

This would would be great!

have you tried with GNU tee and tac instead and do you get the same errors there?

No. How can I run the cargo tests with gnu?

@tertsdiepraam
Copy link
Member

tertsdiepraam commented Nov 23, 2022

Only manually by changing scene.ucmd() to scene.cmd("tac") I think

@Joining7943
Copy link
Contributor Author

Ah ok... I ran the failing test_tee tests:

test_tee::linux_only::test_pipe_error_default
test_tee::linux_only::test_pipe_error_exit
test_tee::linux_only::test_space_error_exit
test_tee::linux_only::test_space_error_exit_nopipe

with gnu's tail and they fail, too.

The tac tests fail only on windows pretty randomly. Can't test with original gnu utils there, I think.

@Joining7943
Copy link
Contributor Author

Joining7943 commented Nov 23, 2022

Here's the test output:

❯ cargo test --features tee --no-default-features -- test_tee::linux_only::test_pipe_error_default test_tee::linux_only::test_pipe_error_exit test_tee::linux_only::test_space_error_exit test_tee::linux_only::test_space_error_exit_nopipe --exact
    Blocking waiting for file lock on package cache
    Blocking waiting for file lock on build directory
   Compiling coreutils v0.0.16 (/home/lenny/workspace/external/uutils/uutils)
    Finished test [unoptimized + debuginfo] target(s) in 9.55s
     Running unittests (target/debug/deps/coreutils-96b5fd9818ad1089)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

     Running tests/test_util_name.rs (target/debug/deps/test_util_name-0e84b12cd99889b1)

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 28 filtered out; finished in 0.00s

     Running tests/tests.rs (target/debug/deps/tests-2d0595bef343d42d)

running 4 tests
test test_tee::linux_only::test_space_error_exit ... FAILED
test test_tee::linux_only::test_pipe_error_exit ... FAILED
test test_tee::linux_only::test_pipe_error_default ... FAILED
test test_tee::linux_only::test_space_error_exit_nopipe ... FAILED

failures:

---- test_tee::linux_only::test_space_error_exit stdout ----
current_directory_resolved:
run: /usr/bin/tee --output-error=exit tee_file_out_a /dev/full
thread 'test_tee::linux_only::test_space_error_exit' panicked at 'called `Result::unwrap()` on an `Err` value: Custom { kind: Other, error: "failed to write to stdin of child: Broken pipe (os error 32)" }', tests/common/util.rs:1724:32
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- test_tee::linux_only::test_pipe_error_exit stdout ----
current_directory_resolved:
run: /usr/bin/tee --output-error=exit tee_file_out_a
thread 'test_tee::linux_only::test_pipe_error_exit' panicked at 'called `Result::unwrap()` on an `Err` value: Custom { kind: Other, error: "failed to write to stdin of child: Broken pipe (os error 32)" }', tests/common/util.rs:1724:32

---- test_tee::linux_only::test_pipe_error_default stdout ----
current_directory_resolved:
run: /usr/bin/tee tee_file_out_a
thread 'test_tee::linux_only::test_pipe_error_default' panicked at 'called `Result::unwrap()` on an `Err` value: Custom { kind: Other, error: "failed to write to stdin of child: Broken pipe (os error 32)" }', tests/common/util.rs:1724:32

---- test_tee::linux_only::test_space_error_exit_nopipe stdout ----
current_directory_resolved:
run: /usr/bin/tee --output-error=exit-nopipe tee_file_out_a /dev/full
thread 'test_tee::linux_only::test_space_error_exit_nopipe' panicked at 'called `Result::unwrap()` on an `Err` value: Custom { kind: Other, error: "failed to write to stdin of child: Broken pipe (os error 32)" }', tests/common/util.rs:1724:32


failures:
    test_tee::linux_only::test_pipe_error_default
    test_tee::linux_only::test_pipe_error_exit
    test_tee::linux_only::test_space_error_exit
    test_tee::linux_only::test_space_error_exit_nopipe

test result: FAILED. 0 passed; 4 failed; 0 ignored; 0 measured; 44 filtered out; finished in 0.12s

@Joining7943
Copy link
Contributor Author

My current state of investigation is:
Regarding the tee tests, I think that ignore_stdin_write_error should be fine. This was the situation before UChild.

Regarding the tac tests, I would like to disable them on windows.

@Joining7943 Joining7943 changed the title tests/tail: Test runner implementation tests/common/util: Implement UChild, an abstraction for std::process::Child, to return UChild from run_no_wait instead Nov 23, 2022
Copy link
Member

@tertsdiepraam tertsdiepraam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love where this is headed. Most of my comments are focused on removing or hiding parts of the API, I think we should make this as simple as possible for contributors to understand (and the test framework has already a very big API).

I'm also gonna say this now, before we move further. You've got a lot of commits here, but the changes are too big that I don't want to squash them all into one. So it'd be great if you could do some cleanup yourself there.

As for tac, maybe pipe_in_and_wait is wrong and it's some concurrency bug? Maybe it exists without the thread having written anything somehow.

tests/common/util.rs Outdated Show resolved Hide resolved
tests/common/util.rs Outdated Show resolved Hide resolved
tests/common/util.rs Outdated Show resolved Hide resolved
tests/common/util.rs Outdated Show resolved Hide resolved
tests/common/util.rs Outdated Show resolved Hide resolved
tests/common/util.rs Outdated Show resolved Hide resolved
tests/common/util.rs Outdated Show resolved Hide resolved
tests/common/util.rs Outdated Show resolved Hide resolved
tests/common/util.rs Show resolved Hide resolved
tests/common/util.rs Outdated Show resolved Hide resolved
sylvestre pushed a commit to Joining7943/uutil-coreutils that referenced this pull request Nov 29, 2022
…e tests on windows.

Summary:
* Disable test_retry6 on android because of intermittent failures
* Use wait() instead of wait_with_output in test_cat, test_cp, test_sort
* tests/sort: Simplify usage of test_sigpipe_panic
* Fix tests in test_tee.

tests/tac:
There was a change in the `tests/common/util.rs` test api concerning piped input which may have
revealed a bug in the implementation of tac. Please see also
uutils#4136
tests/by-util/test_tac.rs Outdated Show resolved Hide resolved
tests/by-util/test_tac.rs Outdated Show resolved Hide resolved
tests/by-util/test_tail.rs Show resolved Hide resolved
@tertsdiepraam
Copy link
Member

Are we ready, here?

Almost, it all looks great and it's just the clippy things now!

@github-actions
Copy link

GNU testsuite comparison:

GNU test failed: tests/tail-2/inotify-dir-recreate. tests/tail-2/inotify-dir-recreate is passing on 'main'. Maybe you have to rebase?

Joining7943 added a commit to Joining7943/uutil-coreutils that referenced this pull request Nov 30, 2022
…e tests on windows.

Summary:
* Disable test_retry6 on android because of intermittent failures
* Use wait() instead of wait_with_output in test_cat, test_cp, test_sort
* tests/sort: Simplify usage of test_sigpipe_panic
* Fix tests in test_tee.

tests/tac:
There was a change in the `tests/common/util.rs` test api concerning piped input which may have
revealed a bug in the implementation of tac. Please see also
uutils#4136
@github-actions
Copy link

GNU testsuite comparison:

GNU test failed: tests/tail-2/inotify-dir-recreate. tests/tail-2/inotify-dir-recreate is passing on 'main'. Maybe you have to rebase?

Joining7943 added a commit to Joining7943/uutil-coreutils that referenced this pull request Dec 1, 2022
Joining7943 added a commit to Joining7943/uutil-coreutils that referenced this pull request Dec 1, 2022
…e tests on windows.

Summary:
* Disable test_retry6 on android because of intermittent failures
* Use wait() instead of wait_with_output in test_cat, test_cp, test_sort
* tests/sort: Simplify usage of test_sigpipe_panic
* Fix tests in test_tee.

tests/tac:
There was a change in the `tests/common/util.rs` test api concerning piped input which may have
revealed a bug in the implementation of tac. Please see also
uutils#4136
@github-actions
Copy link

github-actions bot commented Dec 1, 2022

GNU testsuite comparison:

Congrats! The gnu test tests/tail-2/inotify-dir-recreate is no longer failing!

@github-actions
Copy link

github-actions bot commented Dec 1, 2022

GNU testsuite comparison:

GNU test failed: tests/misc/tee. tests/misc/tee is passing on 'main'. Maybe you have to rebase?

…nd return UChild

tests/tail:
* test_stdin_redirect_file:. Test fails now when assert_alive()!
The follow test `tail -f < file` where file's content is `foo` fails with:
    Assertion failed. Expected 'tail' to be running but exited with status=exit status: 0

I also tried on the command line and can confirm that tail isn't runnning when following by
descriptor. The test is deactivated until the implementation is fixed.

* test_follow_stdin_descriptor
* test_follow_stdin_explicit_indefinitely.
* test_follow_single
* test_follow_non_utf8_bytes
* test_follow_multiple
* test_follow_name_multiple
* test_follow_invalid_pid
* test_single_big_args
* test_retry3
* test_retry4
* test_retry5
* test_retry7
* test_retry8
* test_retry9
* test_follow_descriptor_vs_rename1
* test_follow_descriptor_vs_rename2
* test_follow_name_retry_headers
* test_follow_name_remove
* test_follow_name_truncate1
* test_follow_name_truncate2
* test_follow_name_truncate3
* test_follow_name_truncate4
* test_follow_truncate_fast
* test_follow_name_move_create1
* test_follow_name_move_create2
* test_follow_name_move1
* test_follow_name_move2
* test_follow_name_move_retry1
* test_follow_name_move_retry2
* test_follow_inotify_only_regular
* test_fifo
* test_illegal_seek

tests/cat:
* test_dev_full
* test_dev_full_show_all
* test_dev_random
* test_fifo_symlink

tests/dd:
* test_random_73k_test_lazy_fullblock
* test_sync_delayed_reader

tests/factor:
* test_parallel

tests/rm:
* test_rm_force_prompts_order
* test_rm_descend_directory
* test_rm_prompts

tests/seq:
* the helper run method

tests/sort:
* test_sigpipe_panic

tests/tee:
* the helper run_tee method

tests/tty:
* test_tty module

tests/yes:
* the helper run method
A short summary of changes:

* Add some basic tests for UChild and the run methods.
* Try more often in a fixed interval to create the tempfile for CapturedOutput.
* Fix drop order of struct fields for better cleanup of temporary files/dirs.
* Mark UChild::wait_with_output and UChild::pipe_in_and_wait_with_output deprecated
* Make CapturedOutput private
* Panic in stdout_all, stdout_all_bytes etc. if output is not captured.
* Rename some methods, refactor, clean up, fix documentation, add try_... methods
Joining7943 added a commit to Joining7943/uutil-coreutils that referenced this pull request Dec 2, 2022
…e tests on windows.

Summary:
* Disable test_retry6 on android because of intermittent failures
* Use wait() instead of wait_with_output in test_cat, test_cp, test_sort
* tests/sort: Simplify usage of test_sigpipe_panic
* Fix tests in test_tee.

tests/tac:
There was a change in the `tests/common/util.rs` test api concerning piped input which may have
revealed a bug in the implementation of tac. Please see also
uutils#4136
tests/common/util.rs Outdated Show resolved Hide resolved
…e tests on windows.

Summary:
* Disable test_retry6 on android because of intermittent failures
* Use wait() instead of wait_with_output in test_cat, test_cp, test_sort
* tests/sort: Simplify usage of test_sigpipe_panic
* Fix tests in test_tee.

tests/tac:
There was a change in the `tests/common/util.rs` test api concerning piped input which may have
revealed a bug in the implementation of tac. Please see also
uutils#4136
Copy link
Member

@tertsdiepraam tertsdiepraam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice! I'm super happy with how this turned out! Thanks!

@Joining7943
Copy link
Contributor Author

Sure. I'm glad to hear.

@github-actions
Copy link

github-actions bot commented Dec 2, 2022

GNU testsuite comparison:

GNU test failed: tests/tail-2/inotify-dir-recreate. tests/tail-2/inotify-dir-recreate is passing on 'main'. Maybe you have to rebase?

@sylvestre sylvestre merged commit 75502ab into uutils:main Dec 3, 2022
@sylvestre
Copy link
Contributor

looks great indeed, thanks :)

@Joining7943 Joining7943 deleted the tail-test-runner branch January 2, 2023 09:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants