Skip to content

Commit

Permalink
feat(dif): Fail debug-files upload when file is too big (#2331)
Browse files Browse the repository at this point in the history
Previously, we only logged an easy-to-miss warning when we had to skip
uploading a debug file because it was too big. Now, we instead fail the
entire upload loudly, to ensure users do not miss this important
information.

Resolves #2313
  • Loading branch information
szokeasaurusrex authored Jan 7, 2025
1 parent ad7e037 commit 739bc00
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 20 deletions.
43 changes: 38 additions & 5 deletions src/utils/dif_upload/error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Error types for the dif_upload module.
use anyhow::Result;
use indicatif::HumanBytes;
use thiserror::Error;

Expand All @@ -21,13 +22,45 @@ pub enum ValidationError {
}

/// Handles a DIF validation error by logging it to console
/// at the appropriate log level.
pub fn handle(dif_name: &str, error: &ValidationError) {
let message = format!("Skipping {}: {}", dif_name, error);
/// at the appropriate log level. Or, if the error should stop
/// the upload, it will return an error, that can be propagated
/// to the caller.
pub fn handle(dif_name: &str, error: &ValidationError) -> Result<()> {
let message = format!("{}: {}", dif_name, error);
match error {
ValidationError::InvalidFormat
| ValidationError::InvalidFeatures
| ValidationError::InvalidDebugId => log::debug!("{message}"),
ValidationError::TooLarge { .. } => log::warn!("{message}"),
| ValidationError::InvalidDebugId => log::debug!("Skipping {message}"),
ValidationError::TooLarge { .. } => {
anyhow::bail!("Upload failed due to error in debug file {message}")
}
}

Ok(())
}

#[cfg(test)]
mod tests {
use super::*;

use rstest::rstest;

#[rstest]
#[case(ValidationError::InvalidFormat)]
#[case(ValidationError::InvalidFeatures)]
#[case(ValidationError::InvalidDebugId)]
fn test_handle_should_not_error(#[case] error: ValidationError) {
let result = handle("test", &error);
assert!(result.is_ok());
}

#[test]
fn test_handle_should_error() {
let error = ValidationError::TooLarge {
size: 1000,
max_size: 100,
};
let result = handle("test", &error);
assert!(result.is_err());
}
}
30 changes: 15 additions & 15 deletions src/utils/dif_upload/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -658,14 +658,14 @@ fn search_difs(options: &DifUpload) -> Result<Vec<DifMatch<'static>>> {

if Archive::peek(&buffer) != FileFormat::Unknown {
let mut difs =
collect_object_dif(source, name, buffer, options, &mut age_overrides);
collect_object_dif(source, name, buffer, options, &mut age_overrides)?;
collected.append(difs.as_mut());
} else if BcSymbolMap::test(&buffer) {
if let Some(dif) = collect_auxdif(name, buffer, options, AuxDifKind::BcSymbolMap) {
if let Some(dif) = collect_auxdif(name, buffer, options, AuxDifKind::BcSymbolMap)? {
collected.push(dif);
}
} else if buffer.starts_with(b"<?xml") {
if let Some(dif) = collect_auxdif(name, buffer, options, AuxDifKind::UuidMap) {
if let Some(dif) = collect_auxdif(name, buffer, options, AuxDifKind::UuidMap)? {
collected.push(dif);
}
};
Expand Down Expand Up @@ -731,7 +731,7 @@ fn collect_auxdif<'a>(
buffer: ByteView<'static>,
options: &DifUpload,
kind: AuxDifKind,
) -> Option<DifMatch<'a>> {
) -> Result<Option<DifMatch<'a>>> {
let file_stem = Path::new(&name)
.file_stem()
.map(|stem| stem.to_string_lossy())
Expand All @@ -748,7 +748,7 @@ fn collect_auxdif<'a>(
name = name
);
}
return None;
return Ok(None);
}
};
let dif_result = match kind {
Expand All @@ -764,17 +764,17 @@ fn collect_auxdif<'a>(
name = name,
err = err
);
return None;
return Ok(None);
}
};

// Skip this file if we don't want to process it.
if let Err(e) = options.validate_dif(&dif) {
error::handle(&name, &e);
return None;
error::handle(&name, &e)?;
return Ok(None);
}

Some(dif)
Ok(Some(dif))
}

/// Processes and [`DifSource`] which is expected to be an object file.
Expand All @@ -784,7 +784,7 @@ fn collect_object_dif<'a>(
buffer: ByteView<'static>,
options: &DifUpload,
age_overrides: &mut BTreeMap<Uuid, u32>,
) -> Vec<DifMatch<'a>> {
) -> Result<Vec<DifMatch<'a>>> {
let mut collected = Vec::with_capacity(2);

// Try to parse a potential object file. If this is not possible,
Expand All @@ -799,15 +799,15 @@ fn collect_object_dif<'a>(
format == FileFormat::Pe && options.valid_format(DifFormat::Object(FileFormat::Pdb));

if !should_override_age && !options.valid_format(DifFormat::Object(format)) {
return collected;
return Ok(collected);
}

debug!("trying to parse dif {}", name);
let archive = match Archive::parse(&buffer) {
Ok(archive) => archive,
Err(e) => {
warn!("Skipping invalid debug file {}: {}", name, e);
return collected;
return Ok(collected);
}
};

Expand Down Expand Up @@ -840,7 +840,7 @@ fn collect_object_dif<'a>(
if let Object::Pe(pe) = &object {
if let Ok(Some(ppdb_dif)) = extract_embedded_ppdb(pe, name.as_str()) {
if let Err(e) = options.validate_dif(&ppdb_dif) {
error::handle(&ppdb_dif.name, &e);
error::handle(&ppdb_dif.name, &e)?;
} else {
collected.push(ppdb_dif);
}
Expand Down Expand Up @@ -884,14 +884,14 @@ fn collect_object_dif<'a>(

// Skip this file if we don't want to process it.
if let Err(e) = options.validate_dif(&dif) {
error::handle(&name, &e);
error::handle(&name, &e)?;
continue;
}

collected.push(dif);
}

collected
Ok(collected)
}

/// Resolves BCSymbolMaps and replaces hidden symbols in a `DifMatch` using
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"url": "organizations/wat-org/chunk-upload/",
"chunkSize": 8388608,
"chunksPerRequest": 64,
"maxFileSize": 2048,
"maxRequestSize": 33554432,
"concurrency": 8,
"hashAlgorithm": "sha1",
"compression": ["gzip"],
"accept": ["debug_files", "release_files", "pdbs", "portablepdbs", "sources", "bcsymbolmaps"]
}
16 changes: 16 additions & 0 deletions tests/integration/debug_files/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -731,3 +731,19 @@ fn chunk_upload_multiple_files_small_chunks_only_some() {
"Uploaded chunks differ from the expected chunks"
);
}

#[test]
fn test_dif_too_big() {
TestManager::new()
.mock_endpoint(
MockEndpointBuilder::new("GET", "/api/0/organizations/wat-org/chunk-upload/")
.with_response_file("debug_files/get-chunk-upload-small-max-size.json"),
)
.assert_cmd(vec![
"debug-files",
"upload",
"tests/integration/_fixtures/SrcGenSampleApp.pdb",
])
.with_default_token()
.run_and_assert(AssertCommand::Failure);
}
3 changes: 3 additions & 0 deletions tests/integration/test_utils/test_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ pub struct AssertCmdTestManager {
pub enum AssertCommand {
/// Assert that the command succeeds (i.e. returns a `0` exit code).
Success,
/// Assert that the command fails (i.e. returns a non-zero exit code).
Failure,
}

impl AssertCmdTestManager {
Expand Down Expand Up @@ -219,6 +221,7 @@ impl AssertCmdTestManager {

match assert {
AssertCommand::Success => command_result.success(),
AssertCommand::Failure => command_result.failure(),
};
}

Expand Down

0 comments on commit 739bc00

Please sign in to comment.