Skip to content

Commit e749061

Browse files
committed
add tests; review error handling
1 parent 52e0244 commit e749061

File tree

7 files changed

+389
-136
lines changed

7 files changed

+389
-136
lines changed

cpp-linter/src/clang_tools/clang_format.rs

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -160,17 +160,13 @@ pub fn run_clang_format(
160160
.output()
161161
.with_context(|| format!("Failed to get replacements from clang-format: {file_name}"))?;
162162
if !output.stderr.is_empty() || !output.status.success() {
163-
if let Ok(stderr) = String::from_utf8(output.stderr) {
164-
logs.push((
165-
log::Level::Debug,
166-
format!("clang-format raised the follow errors:\n{}", stderr),
167-
));
168-
} else {
169-
logs.push((
170-
log::Level::Error,
171-
"stderr from clang-format was not UTF-8 encoded".to_string(),
172-
));
173-
}
163+
logs.push((
164+
log::Level::Debug,
165+
format!(
166+
"clang-format raised the follow errors:\n{}",
167+
String::from_utf8_lossy(&output.stderr)
168+
),
169+
));
174170
}
175171
if output.stdout.is_empty() {
176172
return Ok(logs);

cpp-linter/src/clang_tools/clang_tidy.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -304,21 +304,17 @@ pub fn run_clang_tidy(
304304
log::Level::Debug,
305305
format!(
306306
"Output from clang-tidy:\n{}",
307-
String::from_utf8(output.stdout.to_vec()).unwrap()
307+
String::from_utf8_lossy(&output.stdout)
308308
),
309309
));
310310
if !output.stderr.is_empty() {
311-
if let Ok(stderr) = String::from_utf8(output.stderr) {
312-
logs.push((
313-
log::Level::Debug,
314-
format!("clang-tidy made the following summary:\n{}", stderr),
315-
));
316-
} else {
317-
logs.push((
318-
log::Level::Error,
319-
"clang-tidy stderr is not UTF-8 encoded".to_string(),
320-
));
321-
}
311+
logs.push((
312+
log::Level::Debug,
313+
format!(
314+
"clang-tidy made the following summary:\n{}",
315+
String::from_utf8_lossy(&output.stderr)
316+
),
317+
));
322318
}
323319
file.tidy_advice = parse_tidy_output(&output.stdout, &clang_params.database_json)?;
324320
if clang_params.tidy_review {

cpp-linter/src/rest_api/github/mod.rs

Lines changed: 33 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -292,31 +292,31 @@ mod test {
292292
default::Default,
293293
env,
294294
io::Read,
295-
path::PathBuf,
295+
path::{Path, PathBuf},
296296
sync::{Arc, Mutex},
297297
};
298298

299-
use chrono::Utc;
300-
use mockito::{Matcher, Server};
301299
use regex::Regex;
302-
use reqwest::{Method, Url};
303300
use tempfile::{tempdir, NamedTempFile};
304301

305302
use super::GithubApiClient;
306303
use crate::{
307304
clang_tools::capture_clang_tools_output,
308305
cli::{ClangParams, FeedbackInput, LinesChangedOnly},
309-
common_fs::FileObj,
306+
common_fs::{FileFilter, FileObj},
307+
logger,
310308
rest_api::{RestApiClient, USER_OUTREACH},
311309
};
312310

313311
// ************************* tests for step-summary and output variables
314312

315-
async fn create_comment(tidy_checks: &str, style: &str) -> (String, String) {
313+
async fn create_comment(tidy_checks: &str, style: &str, fail_gh_out: bool) -> (String, String) {
316314
let tmp_dir = tempdir().unwrap();
317315
let rest_api_client = GithubApiClient::new().unwrap();
316+
logger::init().unwrap();
318317
if env::var("ACTIONS_STEP_DEBUG").is_ok_and(|var| var == "true") {
319318
assert!(rest_api_client.debug_enabled);
319+
log::set_max_level(log::LevelFilter::Debug);
320320
}
321321
let mut files = vec![Arc::new(Mutex::new(FileObj::new(PathBuf::from(
322322
"tests/demo/demo.cpp",
@@ -342,7 +342,14 @@ mod test {
342342
let mut step_summary_path = NamedTempFile::new_in(tmp_dir.path()).unwrap();
343343
env::set_var("GITHUB_STEP_SUMMARY", step_summary_path.path());
344344
let mut gh_out_path = NamedTempFile::new_in(tmp_dir.path()).unwrap();
345-
env::set_var("GITHUB_OUTPUT", gh_out_path.path());
345+
env::set_var(
346+
"GITHUB_OUTPUT",
347+
if fail_gh_out {
348+
Path::new("not-a-file.txt")
349+
} else {
350+
gh_out_path.path()
351+
},
352+
);
346353
rest_api_client
347354
.post_feedback(&files, feedback_inputs)
348355
.await
@@ -354,13 +361,15 @@ mod test {
354361
assert!(&step_summary_content.contains(USER_OUTREACH));
355362
let mut gh_out_content = String::new();
356363
gh_out_path.read_to_string(&mut gh_out_content).unwrap();
357-
assert!(gh_out_content.starts_with("checks-failed="));
364+
if !fail_gh_out {
365+
assert!(gh_out_content.starts_with("checks-failed="));
366+
}
358367
(step_summary_content, gh_out_content)
359368
}
360369

361370
#[tokio::test]
362371
async fn check_comment_concerns() {
363-
let (comment, gh_out) = create_comment("readability-*", "file").await;
372+
let (comment, gh_out) = create_comment("readability-*", "file", false).await;
364373
assert!(&comment.contains(":warning:\nSome files did not pass the configured checks!\n"));
365374
let fmt_pattern = Regex::new(r"format-checks-failed=(\d+)\n").unwrap();
366375
let tidy_pattern = Regex::new(r"tidy-checks-failed=(\d+)\n").unwrap();
@@ -380,61 +389,31 @@ mod test {
380389
#[tokio::test]
381390
async fn check_comment_lgtm() {
382391
env::set_var("ACTIONS_STEP_DEBUG", "true");
383-
let (comment, gh_out) = create_comment("-*", "").await;
392+
let (comment, gh_out) = create_comment("-*", "", false).await;
384393
assert!(&comment.contains(":heavy_check_mark:\nNo problems need attention."));
385394
assert_eq!(
386395
&gh_out,
387396
"checks-failed=0\nformat-checks-failed=0\ntidy-checks-failed=0\n"
388397
);
389398
}
390399

391-
async fn simulate_rate_limit(secondary: bool) {
392-
let mut server = Server::new_async().await;
393-
let url = Url::parse(server.url().as_str()).unwrap();
394-
env::set_var("GITHUB_API_URL", server.url());
395-
let client = GithubApiClient::new().unwrap();
396-
let reset_timestamp = (Utc::now().timestamp() + 60).to_string();
397-
let mock = server
398-
.mock("GET", "/")
399-
.match_body(Matcher::Any)
400-
.expect_at_least(1)
401-
.expect_at_most(5)
402-
.with_status(429)
403-
.with_header(
404-
&client.rate_limit_headers.remaining,
405-
if secondary { "1" } else { "0" },
406-
)
407-
.with_header(&client.rate_limit_headers.reset, &reset_timestamp);
408-
if secondary {
409-
mock.with_header(&client.rate_limit_headers.retry, "0")
410-
.create();
411-
} else {
412-
mock.create();
413-
}
414-
let request =
415-
GithubApiClient::make_api_request(&client.client, url, Method::GET, None, None)
416-
.unwrap();
417-
GithubApiClient::send_api_request(
418-
client.client.clone(),
419-
request,
420-
client.rate_limit_headers.clone(),
421-
0,
422-
)
423-
.await
424-
.unwrap();
425-
}
426-
427400
#[tokio::test]
428-
#[ignore]
429-
#[should_panic(expected = "REST API secondary rate limit exceeded")]
430-
async fn secondary_rate_limit() {
431-
simulate_rate_limit(true).await;
401+
async fn fail_gh_output() {
402+
env::set_var("ACTIONS_STEP_DEBUG", "true");
403+
let (comment, gh_out) = create_comment("-*", "", true).await;
404+
assert!(&comment.contains(":heavy_check_mark:\nNo problems need attention."));
405+
assert_eq!(&gh_out, "");
432406
}
433407

434408
#[tokio::test]
435-
#[ignore]
436-
#[should_panic(expected = "REST API rate limit exceeded!")]
437-
async fn primary_rate_limit() {
438-
simulate_rate_limit(false).await;
409+
async fn fail_get_local_diff() {
410+
env::set_var("CI", "false");
411+
let tmp_dir = tempdir().unwrap();
412+
env::set_current_dir(tmp_dir.path()).unwrap();
413+
let rest_client = GithubApiClient::new().unwrap();
414+
let files = rest_client
415+
.get_list_of_changed_files(&FileFilter::new(&[], vec![]))
416+
.await;
417+
assert!(files.is_err())
439418
}
440419
}

cpp-linter/src/rest_api/github/specific_api.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ impl GithubApiClient {
3030
let pull_request = {
3131
match event_name.as_str() {
3232
"pull_request" => {
33-
let event_payload_path = env::var("GITHUB_EVENT_PATH").with_context(|| {
34-
"GITHUB_EVENT_NAME is set to 'pull_request', but GITHUB_EVENT_PATH is not set"
35-
})?;
33+
// GITHUB_*** env vars cannot be overwritten in CI runners on GitHub.
34+
let event_payload_path = env::var("GITHUB_EVENT_PATH")?;
35+
// event payload JSON file can be overwritten/removed in CI runners
3636
let file_buf = &mut String::new();
3737
OpenOptions::new()
3838
.read(true)
@@ -51,16 +51,15 @@ impl GithubApiClient {
5151
_ => None,
5252
}
5353
};
54+
// GITHUB_*** env vars cannot be overwritten in CI runners on GitHub.
5455
let gh_api_url = env::var("GITHUB_API_URL").unwrap_or("https://api.github.com".to_string());
55-
let api_url = Url::parse(gh_api_url.clone().as_str())
56-
.with_context(|| format!("Failed to parse URL from GITHUB_API_URL: {}", gh_api_url))?;
56+
let api_url = Url::parse(gh_api_url.as_str())?;
5757

5858
Ok(GithubApiClient {
5959
client: Client::builder()
6060
.default_headers(Self::make_headers()?)
6161
.user_agent(USER_AGENT)
62-
.build()
63-
.with_context(|| "Failed to create a session client for REST API calls")?,
62+
.build()?,
6463
pull_request,
6564
event_name,
6665
api_url,
@@ -87,6 +86,7 @@ impl GithubApiClient {
8786
/// Append step summary to CI workflow's summary page.
8887
pub fn post_step_summary(&self, comment: &String) {
8988
if let Ok(gh_out) = env::var("GITHUB_STEP_SUMMARY") {
89+
// step summary MD file can be overwritten/removed in CI runners
9090
if let Ok(mut gh_out_file) = OpenOptions::new().append(true).open(gh_out) {
9191
if let Err(e) = writeln!(gh_out_file, "\n{}\n", comment) {
9292
log::error!("Could not write to GITHUB_STEP_SUMMARY file: {}", e);

0 commit comments

Comments
 (0)