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

Create testsuite for GithubClient #1698

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

ehuss
Copy link
Contributor

@ehuss ehuss commented Jun 7, 2023

This adds a new testsuite for verifying the behavior for GithubClient. This can assist with adding new functions where you can verify that everything is working correctly without having to guess.

In general this works by setting up a simple HTTP server, sending the requests to it, and verifying the responses. Tests can be created by recording against the live GitHub site, but otherwise tests only run against the local test server.

The first commit updates GithubClient so that it can configure the host it connects to.

@ehuss
Copy link
Contributor Author

ehuss commented Jun 7, 2023

This is just the client side of #1678. I'm not sure when I'll be able to make time to finish up the server tests. Those are more complicated and I'm not as confident in them. The client tests are simpler and I think should be reliable and relatively easy to write and run.

@ehuss ehuss force-pushed the gh-test-client branch 3 times, most recently from 60df51b to a47947b Compare June 21, 2023 02:33
@ehuss
Copy link
Contributor Author

ehuss commented Jul 10, 2023

@Mark-Simulacrum Just checking if you'll have a chance to review this. I think this would help with avoiding issues like #1707 where there are issues in the GithubClient. I realize it adds a lot of noisy files, but I think it is important to have real-world data to test against. When reviewing, I suggest just looking at the filenames to get the gist of what a test is doing and to make sure it seems reasonable (like the remove_label does a DELETE on the labels endpoint). I expect any tests added in the future will be a little easier to review since it will be a smaller set of changes.

I also realize writing these tests takes a little effort. However, I've tried to minimize that as much as possible, along with clear step-by-step directions. (But, to be honest, I'll be surprised if anyone writes their own.)

//! look like. To write a test, follow these steps:
//!
//! 1. Choose a repo in your GitHub account to run tests against. I use either
//! `ehuss/rust` or `ehuss/triagebot-test`, but any in your account will do.
Copy link
Member

Choose a reason for hiding this comment

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

Am I right in interpreting this means that if (for example) I adjust the functionality for some test -- passing different parameters, querying slightly different information, etc. -- I have no good way of re-running it without changing lots of irrelevant details in the output? (Since I lack access to your repository for test creation etc.).

I think the tradeoff probably still makes sense - in practice hopefully we can avoid updating these files too much -- but would like to hear your take on that.

Copy link
Contributor

Choose a reason for hiding this comment

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

a variant of the above comment: is there a way to regenerate the JSON files automatically - in case of said small change? maybe I think no, right? You have to delete all of the relevant JSON test files, make said small change, re-run the tests and try to diff the new JSON generated files?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yea, regenerating an existing test is not particularly easy. My expectation is that the process would look like:

  1. Make a change to GithubClient.
  2. Edit the test to point to a repo you control (like Mark-Simulacrum/rust).
  3. Re-record the test using TRIAGEBOT_TEST_RECORD_DIR=github_client/TEST_NAME_HERE cargo test --test testsuite -- --exact github_client::TEST_NAME_HERE
  4. Add any new assertions relevant to your change (or fix any errors with the existing assertions).

Unfortunately some of the tests have setup that is required (like creating a PR, creating labels, etc.) that the tests currently don't do (I did that manually). I can look at making those tests do all the setup they need. #1678 does this to some degree, but it requires more code to do the setup.

Regenerating all of the JSON files isn't currently possible. The tests need the ability to make changes on the live GitHub site, which means it needs to have a repo that it can write to, and it doesn't know what that is. Per the comment below, I can look at adding that possibility. But that would end up changing all the JSON files causing a large diff.

//!
//! ```sh
//! TRIAGEBOT_TEST_RECORD_DIR=github_client/TEST_NAME_HERE cargo test \
//! --test testsuite -- --exact github_client::TEST_NAME_HERE
Copy link
Member

Choose a reason for hiding this comment

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

How hard would it be to have a mode that runs the full test suite and checks/updates recordings against a repo that we control? e.g., rustbot/rust or similar?

My main worry about this design is that it gives us potentially false confidence if GitHub's APIs change, and it's somewhat painful to actually update when they do (potentially lots of local setup) vs. something that ideally we could run in CI, perhaps post-merge. Especially if we expect that new tests are primarily authored by "authorized" folks, we could have the CI in question be kickable with e.g. bors try or similar.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can take a look at making it easier to re-bless all of the tests using a single repo.

One concern is that if you just blanket re-record all of the tests, that will cause a very large diff since almost all of the data will change.

@Mark-Simulacrum
Copy link
Member

I have a few questions, but broadly I'm fine with merging this as-is -- if it gives us pain we can always change course, rather than hashing out all the details up front.

Comment on lines +17 to +20
//! **WARNING**: Do not write tests that modify the rust-lang org repos
//! like rust-lang/rust. Write those tests against your own fork (like
//! `ehuss/rust`). We don't want to pollute the real repos with things like
//! test PRs.
Copy link
Contributor

@apiraino apiraino Jul 12, 2023

Choose a reason for hiding this comment

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

I understand that the testsuite is meant to be run against your own git repos, but I don't quite understand the sentence "We don't want to pollute the real repos with things like test PRs." (but maybe it's just me)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'll add some clarity to that. I was just meaning, we don't want tests making changes or opening PRs on production repos like https://github.com/rust-lang/rust/.

@@ -115,6 +115,21 @@ You need to sign up for a free account, and also deal with configuring the GitHu
* Secret: Enter a shared secret (some longish random text)
* Events: "Send me everything"

## Tests
Copy link
Contributor

Choose a reason for hiding this comment

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

@ehuss by reading this README snippet I don't easily understand at a glance how the testsuite is meant to be used and maintained. Is the documentation actually meant to be in tests/github_client/mod.rs as rustdoc's comments?

A few questions ahead. Sorry for the perhaps vague comments 🙂, I'm trying to squint and understand these changes and their mainteinance cost for future other contributors:

  • What is needed to test a new handler under ./src/handlers (which is something I'm currently doing)? I assume little to nothing if the new handler is just using the same Github API already tested, right?

  • (echoing the comment from Mark) What is needed to do to update tests? Say, we change a little something in how we interpret Github responses in some structs under ./src/github.rs?

  • is there a way to regenerate these JSON files automatically?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is the documentation actually meant to be in tests/github_client/mod.rs as rustdoc's comments?

I'm not quite sure I understand the question. The documentation in README.md is intended as a high-level overview of testing of triagebot, and includes a link to tests/github_client/mod.rs to read more details of that specific test suite. If and when more suites are added, they could be linked here, too.

What is needed to test a new handler under ./src/handlers (which is something I'm currently doing)? I assume little to nothing if the new handler is just using the same Github API already tested, right?

Right, handler testing isn't part of this PR. Testing of handlers is implemented in #1678, but I'm finding them to be even harder to wield than these tests, so I broke out just the github side of things to try to make some progress.

What is needed to do to update tests? Say, we change a little something in how we interpret Github responses in some structs under ./src/github.rs?

As mentioned above. The general process is to point the test at one of your personal repos, and re-record the live data.

is there a way to regenerate these JSON files automatically?

Also mentioned above. I can take a look at making it easier to regenerate them.

Copy link
Contributor

@apiraino apiraino left a comment

Choose a reason for hiding this comment

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

I am trying to understand these changes. What if we want to add other server endpoints - say Zulip ones? Do we need to entirely duplicate ./tests/testsuite.rs and tests/github_client/mod.rs and change bits here and there?

@apiraino
Copy link
Contributor

@ehuss IIUC there's no Rust crate that could provide a satisfactory solution so we're rolling our own, correct?

@apiraino
Copy link
Contributor

apiraino commented Jul 12, 2023

I also realize writing these tests takes a little effort. However, I've tried to minimize that as much as possible, along with clear step-by-step directions. (But, to be honest, I'll be surprised if anyone writes their own.)

if you suspect that hardly anyone will write their own tests with the current testsuite drafted here, wouldn't that diminish its usefulness? is there a way to make them more palatable?

(I'm trying to look at this patch through the lens of a possibly new contributor)

EDIT: fixed spelling

@ehuss
Copy link
Contributor Author

ehuss commented Jul 18, 2023

I am trying to understand these changes. What if we want to add other server endpoints - say Zulip ones? Do we need to entirely duplicate ./tests/testsuite.rs and tests/github_client/mod.rs and change bits here and there?

The intent is that tests/testsuite.rs is a base that can be used for recording and mocking services. I haven't looked at mocking Zulip, yet, but I assume it should be relatively easy.

#1678 demonstrates how other test suites can be built upon tests/testsuite.rs. tests/server_test/mod.rs is an example of the webhook server tests (that handles triagebot handlers and such).

If there is another suite (like Zulip) that needs something similar to what is in github_client/mod.rs, I figure it can be factored out if necessary. For the server tests, there wasn't anything else that was shareable.

@ehuss IIUC there's no Rust crate that could provide a satisfactory solution so we're rolling our own, correct?

I'm not sure if you mean for testing, or for the github client itself. For testing, I'm not aware of something that does exactly something like this. Octocrab uses wiremock, but I don't see a way to record live site data with that. The original approach in #1678 was to have hand-crafted mocked endpoints, but that takes a lot more work to set up correctly, so that's why I added the automatic recording.

if you suspect that anyone will write their own tests with the current testsuite drafted here, wouldn't that diminish its usefulness? is there a way to make them more palatable?

I'm not sure it would diminish it. It would just mean that new endpoints wouldn't be tested. It would be nice to have people be willing to participate in setting up tests. I was just saying that from the more cynical side of me that knows many people don't like writing tests.

I'd like to make it more palatable, though I'd like some feedback on what specifically looks challenging. I felt like they were pretty easy for me to write (each test took about 5 minutes to write). If you were writing a test, which step seems difficult or something you would be unwilling to do? I tried to make it as easy as I possibly could, but there weren't any more steps I could remove. I think the TRIAGEBOT_TEST_RECORD_DIR thing is cumbersome, and I could look at writing something like an xtask to simplify that command (like cargo xtask-record TESTNAME). Let me know if you have ideas on how to make it better, or what looks particularly troublesome.

@apiraino
Copy link
Contributor

@ehuss IIUC there's no Rust crate that could provide a satisfactory solution so we're rolling our own, correct?

I'm not sure if you mean for testing, or for the github client itself. For testing, I'm not aware of something that does exactly something like this. Octocrab uses wiremock, but I don't see a way to record live site data with that. The original approach in #1678 was to have hand-crafted mocked endpoints, but that takes a lot more work to set up correctly, so that's why I added the automatic recording.

To be honest I just have a feeling that we are reinventing the wheel (and then we have to maintain it). The specific wheel I suspect we are reinventing is cargo-insta but if cargo-insta does not what you want to implement, then let's roll our own :)

@ehuss thanks for your patience and replies to all my questions :)

@ehuss
Copy link
Contributor Author

ehuss commented Jul 18, 2023

@ehuss thanks for your patience and replies to all my questions :)

I neglected to say this earlier, but thank you for the review and feedback! It is useful, and I'll try to hone this to improve it from that. Questions are very much encouraged.

@jackh726
Copy link
Member

Hi @ehuss, I'd like to work to get this landed.

The first commit (configure API URLs) seems like it would be good to land on its own. Can you split that out and I'll merge it?

Copy link
Member

@jackh726 jackh726 left a comment

Choose a reason for hiding this comment

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

A few initial comments

@@ -1066,6 +1082,15 @@ impl Repository {
|| filters.iter().any(|&(key, _)| key == "no")
|| is_pr && !include_labels.is_empty();

let set_is_pr = |issues: &mut [Issue]| {
Copy link
Member

Choose a reason for hiding this comment

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

This could use a comment!

@@ -1562,6 +1589,16 @@ impl Repository {
})?;
Ok(())
}

pub async fn get_pr(&self, client: &GithubClient, number: u64) -> anyhow::Result<Issue> {
Copy link
Member

Choose a reason for hiding this comment

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

Is this used anywhere?

src/github.rs Show resolved Hide resolved
@ehuss
Copy link
Contributor Author

ehuss commented Jan 22, 2024

The first commit (configure API URLs) seems like it would be good to land on its own. Can you split that out and I'll merge it?

Sure, I went ahead and posted #1764.

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.

4 participants