diff --git a/README.md b/README.md index 85216d9a..147407a5 100644 --- a/README.md +++ b/README.md @@ -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 + +When possible, writing unittests is very helpful and one of the easiest ways to test. +For more advanced testing, there is an integration test called `testsuite` which provides a testing environment for testing triagebot. +At this time, there is one part to it: + +* [`github_client`](tests/github_client/mod.rs) — Tests specifically targeting `GithubClient`. + This sets up an HTTP server that mimics api.github.com and verifies the client's behavior. + +Other parts may be added in the future, such as testing the database or the triagebot server itself. + +The real GitHub API responses are recorded in JSON files that the tests can later replay to verify the behavior of triagebot. +These recordings are enabled with the `TRIAGEBOT_TEST_RECORD_DIR` environment variable. +See the documentation in `github_client` for the steps for setting up recording to write a test. + ## License Triagebot is distributed under the terms of both the MIT license and the diff --git a/src/actions.rs b/src/actions.rs index a87d7fb8..1907195c 100644 --- a/src/actions.rs +++ b/src/actions.rs @@ -3,7 +3,6 @@ use std::collections::HashMap; use std::sync::Arc; use async_trait::async_trait; -use reqwest::Client; use serde::{Deserialize, Serialize}; use tera::{Context, Tera}; @@ -87,7 +86,7 @@ pub fn to_human(d: DateTime) -> String { #[async_trait] impl<'a> Action for Step<'a> { async fn call(&self) -> anyhow::Result { - let gh = GithubClient::new_with_default_token(Client::new()); + let gh = GithubClient::new_from_env(); // retrieve all Rust compiler meetings // from today for 7 days diff --git a/src/github.rs b/src/github.rs index e3aeddde..735616c4 100644 --- a/src/github.rs +++ b/src/github.rs @@ -1,3 +1,4 @@ +use crate::test_record; use anyhow::{anyhow, Context}; use async_trait::async_trait; use bytes::Bytes; @@ -30,15 +31,18 @@ impl GithubClient { .build() .with_context(|| format!("building reqwest {}", req_dbg))?; + let test_capture_info = test_record::capture_request(&req); let mut resp = self.client.execute(req.try_clone().unwrap()).await?; if let Some(sleep) = Self::needs_retry(&resp).await { resp = self.retry(req, sleep, MAX_ATTEMPTS).await?; } + let status = resp.status(); let maybe_err = resp.error_for_status_ref().err(); let body = resp .bytes() .await .with_context(|| format!("failed to read response body {req_dbg}"))?; + test_record::record_request(test_capture_info, status, &body); if let Some(e) = maybe_err { return Err(anyhow::Error::new(e)) .with_context(|| format!("response: {}", String::from_utf8_lossy(&body))); @@ -118,7 +122,7 @@ impl GithubClient { .client .execute( self.client - .get("https://api.github.com/rate_limit") + .get(&format!("{}/rate_limit", self.api_url)) .configure(self) .build() .unwrap(), @@ -171,7 +175,9 @@ impl GithubClient { impl User { pub async fn current(client: &GithubClient) -> anyhow::Result { - client.json(client.get("https://api.github.com/user")).await + client + .json(client.get(&format!("{}/user", client.api_url))) + .await } pub async fn is_team_member<'a>(&'a self, client: &'a GithubClient) -> anyhow::Result { @@ -246,7 +252,7 @@ pub struct Issue { pub number: u64, #[serde(deserialize_with = "opt_string")] pub body: String, - created_at: chrono::DateTime, + pub created_at: chrono::DateTime, pub updated_at: chrono::DateTime, /// The SHA for a merge commit. /// @@ -262,6 +268,7 @@ pub struct Issue { pub html_url: String, pub user: User, pub labels: Vec