Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions cli/src/upload_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub const DRY_RUN_OUTPUT_DIR: &str = "bundle_upload";
pub struct UploadArgs {
#[arg(
long,
required_unless_present_any = [JUNIT_GLOB_REQUIRED_UNLESS_PRESENT_ARG, "bazel_bep_path", "test_reports"],
required_unless_present_any = [JUNIT_GLOB_REQUIRED_UNLESS_PRESENT_ARG, "bazel_bep_path", "test_reports", "swift_test_xunit_paths"],
conflicts_with = "bazel_bep_path",
value_delimiter = ',',
value_parser = clap::builder::NonEmptyStringValueParser::new(),
Expand All @@ -53,20 +53,20 @@ pub struct UploadArgs {
pub junit_paths: Vec<String>,
#[arg(
long,
required_unless_present_any = [JUNIT_GLOB_REQUIRED_UNLESS_PRESENT_ARG, "junit_paths", "test_reports"],
required_unless_present_any = [JUNIT_GLOB_REQUIRED_UNLESS_PRESENT_ARG, "junit_paths", "test_reports", "swift_test_xunit_paths"],
help = "Path to Bazel Build Event Protocol JSON file. BEP files contain test results and build metadata."
)]
pub bazel_bep_path: Option<String>,
#[cfg(target_os = "macos")]
#[arg(long,
required_unless_present_any = ["junit_paths", "bazel_bep_path", "test_reports"],
required_unless_present_any = ["junit_paths", "bazel_bep_path", "test_reports", "swift_test_xunit_paths"],
conflicts_with_all = ["junit_paths", "bazel_bep_path"],
required = false, help = "Path to Xcode XCResult bundle directory (macOS only)."
)]
pub xcresult_path: Option<String>,
#[arg(
long,
required_unless_present_any = [JUNIT_GLOB_REQUIRED_UNLESS_PRESENT_ARG, "junit_paths", "bazel_bep_path"],
required_unless_present_any = [JUNIT_GLOB_REQUIRED_UNLESS_PRESENT_ARG, "junit_paths", "bazel_bep_path", "swift_test_xunit_paths"],
value_delimiter = ',',
value_parser = clap::builder::NonEmptyStringValueParser::new(),
help = "Comma-separated list of glob patterns to test report files. Supports JUnit XML, Bazel BEP, and XCResult formats."
Expand Down
9 changes: 9 additions & 0 deletions cli/tests/common/command_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,6 +436,7 @@ pub enum PathsState {
JunitPaths(String),
BazelBepPath(String),
XCResultPath(String),
SwiftTestXunitPaths(String),
}

impl PathsState {
Expand All @@ -444,6 +445,9 @@ impl PathsState {
PathsState::JunitPaths(path) => vec![String::from("--junit-paths"), path.clone()],
PathsState::BazelBepPath(path) => vec![String::from("--bazel-bep-path"), path.clone()],
PathsState::XCResultPath(path) => vec![String::from("--xcresult-path"), path.clone()],
PathsState::SwiftTestXunitPaths(paths) => {
vec![String::from("--swift-test-xunit-paths"), paths.clone()]
}
}
}
}
Expand Down Expand Up @@ -498,6 +502,11 @@ impl<'b> CommandBuilder<'b> {
self
}

pub fn swift_test_xunit_paths(&mut self, new_paths: &str) -> &mut Self {
self.paths_state = Some(PathsState::SwiftTestXunitPaths(String::from(new_paths)));
self
}

pub fn extra_args(&mut self, args: &[&str]) -> &mut Self {
self.extra_args = args.iter().map(|arg| String::from(*arg)).collect();
self
Expand Down
21 changes: 15 additions & 6 deletions cli/tests/upload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3194,10 +3194,7 @@ async fn upload_bundle_using_swift_test_xunit() {

let state = MockServerBuilder::new().spawn_mock_server().await;
CommandBuilder::upload(temp_dir.path(), state.host.clone())
.extra_args(&[
"--swift-test-xunit-paths",
"xunit-swift-testing.xml,xunit.xml",
])
.swift_test_xunit_paths("xunit-swift-testing.xml,xunit.xml")
.command()
.assert()
.success();
Expand All @@ -3208,7 +3205,7 @@ async fn upload_bundle_using_swift_test_xunit() {
serde_json::from_reader(fs::File::open(tar_extract_directory.join("meta.json")).unwrap())
.unwrap();

let mut files = std::collections::HashMap::new();
let mut cases: Vec<(String, Option<String>)> = Vec::new();
for file_set in &bundle_meta.base_props.file_sets {
for file in &file_set.files {
let mut parser = JunitParser::new();
Expand All @@ -3222,13 +3219,25 @@ async fn upload_bundle_using_swift_test_xunit() {
.iter()
.find(|(key, _)| key.as_str() == "file")
.map(|(_, value)| value.as_str().to_owned());
files.insert(case.name.as_str().to_owned(), file);
cases.push((case.name.as_str().to_owned(), file));
}
}
}
}
}

// Three tests across the two files, each bundled exactly once. A count of six is the
// signature of the same reports arriving through a junit glob as well.
assert_eq!(
cases.len(),
3,
"expected each test bundled once, got {cases:?}"
);

let files = cases
.into_iter()
.collect::<std::collections::HashMap<String, Option<String>>>();

for (name, expected) in [
("helloworld()", "Tests/MyCLITests/TopLevel.swift"),
("shared()", "Tests/MyCLITests/Suites.swift"),
Expand Down
25 changes: 21 additions & 4 deletions xcresult/tests/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,32 @@

#![allow(dead_code)]

use std::{fs::File, path::Path};
use std::{fs::File, path::Path, time::Duration};

use context::repo::RepoUrlParts;
use flate2::read::GzDecoder;
use lazy_static::lazy_static;
use tar::Archive;
use temp_testdir::TempDir;
use xcresult::test_locations::Limits;
#[cfg(target_os = "macos")]
use xcresult::{test_locations::Limits, xcresult::XCResult};
use xcresult::xcresult::XCResult;

/// The limits every test here resolves under.
///
/// The shipped defaults size one resolution on a machine doing nothing else. A test binary
/// starts one language server per test, all of them at once, under coverage instrumentation
/// and alongside the rest of the workspace's suite — and a `sourcekit-lsp` that has not
/// answered `initialize` inside `request_timeout` is abandoned rather than waited on, so
/// every test in that process resolves to nothing. Only the clock is relaxed: what the tests
/// assert on is still resolved the way the defaults resolve it.
pub fn limits() -> Limits {
Limits {
budget: Duration::from_secs(300),
request_timeout: Duration::from_secs(120),
..Limits::default()
}
}

/// The bundles are checked in as tarballs, so a test reads one by unpacking it into a
/// temporary directory that is removed with the `TempDir`.
Expand Down Expand Up @@ -54,7 +71,7 @@ pub fn declaration_report<T: AsRef<Path>, U: AsRef<Path>>(
ORG_URL_SLUG.clone(),
REPO_FULL_NAME.clone(),
repo_root.as_ref(),
Limits::default(),
limits(),
)
.expect("the declaration path reads the bundle");

Expand Down Expand Up @@ -151,7 +168,7 @@ pub fn assert_the_declaration_flag_moves_only_the_file(
ORG_URL_SLUG.clone(),
REPO_FULL_NAME.clone(),
root,
Limits::default(),
limits(),
)
.expect("the declaration path reads the bundle");

Expand Down
9 changes: 6 additions & 3 deletions xcresult/tests/swift_test_xunit.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
//! `swift test --xunit-output` reports no file at all, and needs no Xcode to produce — so
//! this is the shape the declaration path takes on Linux. See the fixture's README.

mod common;

use std::{collections::HashMap, path::Path};

use common::limits;
use rstest::rstest;
use xcresult::test_locations::{Limits, TestKey, TestLocationIndex};
use xcresult::test_locations::{TestKey, TestLocationIndex};
use xcresult::xcrun::find_program;

const FIXTURE_ROOT: &str = "tests/fixture-src/swift-test-xunit";
Expand Down Expand Up @@ -73,7 +76,7 @@ fn resolve_from(xunit: &str) -> HashMap<(String, String), String> {
)
})
.collect::<Vec<_>>();
let index = TestLocationIndex::resolve(Path::new(FIXTURE_ROOT), &keys, Limits::default());
let index = TestLocationIndex::resolve(Path::new(FIXTURE_ROOT), &keys, limits());

cases
.into_iter()
Expand Down Expand Up @@ -233,7 +236,7 @@ mod parity {
String::from("trunk"),
String::from("github.com/trunk-io/analytics-cli"),
Path::new(FIXTURE_ROOT),
Limits::default(),
limits(),
)
.expect("the declaration path reads the bundle");

Expand Down
Loading