diff --git a/tests/create_test.rs b/tests/create_test.rs index 19b4fe6..d1016fb 100644 --- a/tests/create_test.rs +++ b/tests/create_test.rs @@ -4,8 +4,17 @@ use pretty_assertions::assert_eq; use std::{error::Error, fs, path::Path}; mod common; +use serial_test::serial; + +// `#[serial]` because these tests mutate shared fixture state. Two of them run +// against `simple_packs_first_app` -- one creating and deleting `packs/foobaz` +// inside it -- and all four call `common::teardown()`, which removes the cache +// for every fixture, not just the one the calling test used. Run in parallel, +// they delete directories out from under each other, which failed +// `test_create_already_exists` roughly one run in ten. #[test] +#[serial] fn test_create() -> Result<(), Box> { common::delete_foobar(); @@ -67,6 +76,7 @@ See https://github.com/rubyatscale/pks#readme for more info!"); } #[test] +#[serial] fn test_create_with_readme_template_default_path() -> Result<(), Box> { common::delete_foobaz(); @@ -102,6 +112,7 @@ fn test_create_with_readme_template_default_path() -> Result<(), Box> } #[test] +#[serial] fn test_create_with_readme_template_custom_path() -> Result<(), Box> { common::delete_foobar_app_with_custom_readme(); @@ -130,6 +141,7 @@ fn test_create_with_readme_template_custom_path() -> Result<(), Box> } #[test] +#[serial] fn test_create_already_exists() -> Result<(), Box> { cargo_bin_cmd!("pks") .arg("--project-root") diff --git a/tests/gitignore_test.rs b/tests/gitignore_test.rs index fa0a637..790ba8a 100644 --- a/tests/gitignore_test.rs +++ b/tests/gitignore_test.rs @@ -9,9 +9,26 @@ use tempfile::TempDir; mod common; +// Every test below that shells out to `pks` is marked `#[serial]`. +// +// `common::teardown()` globs `tests/fixtures/*/tmp/cache/packwerk` and removes +// the cache for *every* fixture, not just the one the calling test used. Tests +// within a binary run on parallel threads, so one test's teardown could delete a +// directory another test was mid-way through writing into. `pks` creates a cache +// entry with `create_dir_all(parent)` followed by `File::create`, and losing the +// parent between those two calls surfaced as: +// +// Failed to create cache file ".../tmp/cache/packwerk/zeitwerk/": +// Invalid argument (os error 22) +// +// which failed the run about one time in three. Note the cache is written even +// though these fixtures do not set `cache:` -- the constant-resolver cache is +// not governed by that setting, so it cannot be configured away. + /// Test that gitignored files are completely excluded from violation checking. /// The fixture has a violation in ignored_folder/violating.rb which should NOT be reported. #[test] +#[serial] fn test_check_ignores_violations_in_gitignored_files( ) -> Result<(), Box> { // The fixture has: @@ -51,6 +68,7 @@ fn test_check_ignores_violations_in_gitignored_files( /// Test that list-included-files respects gitignore patterns. #[test] +#[serial] fn test_list_included_files_excludes_gitignored() -> Result<(), Box> { let output = Command::new(assert_cmd::cargo::cargo_bin!("pks")) @@ -95,6 +113,7 @@ fn test_list_included_files_excludes_gitignored() -> Result<(), Box> /// Test that the application works correctly even without a .gitignore file. #[test] +#[serial] fn test_check_works_without_gitignore() -> Result<(), Box> { // simple_app doesn't have a .gitignore file // This should still work (and report violations as usual) @@ -186,6 +205,7 @@ fn test_gitignore_matcher_without_gitignore() -> Result<(), Box> { /// CRITICAL: Test that respect_gitignore: false configuration disables gitignore support. #[test] +#[serial] fn test_respect_gitignore_can_be_disabled() -> Result<(), Box> { // The fixture has: // - .gitignore with ignored_folder/ pattern @@ -256,6 +276,7 @@ fn test_gitignore_negation_patterns() -> Result<(), Box> { /// Note: We test this at the library level since .log files aren't Ruby files /// and won't appear in list-included-files regardless of gitignore. #[test] +#[serial] fn test_list_included_files_respects_negation() -> Result<(), Box> { // This is already tested by test_gitignore_negation_patterns at the library level. // At the CLI level, .log files aren't included in list-included-files anyway @@ -403,6 +424,7 @@ fn test_respects_global_gitignore() -> Result<(), Box> { /// Test that gitignore works with the update command. /// Gitignored files should not cause package_todo.yml updates. #[test] +#[serial] fn test_update_respects_gitignore() -> Result<(), Box> { // Create a temporary copy of the fixture let temp_dir = TempDir::new()?;