Skip to content

Commit 77091f1

Browse files
committed
Add some checks to verify the behavior of some error cases for invalid processors.
1 parent 0678e78 commit 77091f1

File tree

1 file changed

+267
-1
lines changed

1 file changed

+267
-1
lines changed

crates/bevy_asset/src/processor/tests.rs

Lines changed: 267 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ use crate::{
3232
meta::AssetMeta,
3333
processor::{
3434
AssetProcessor, LoadTransformAndSave, LogEntry, Process, ProcessContext, ProcessError,
35-
ProcessorState, ProcessorTransactionLog, ProcessorTransactionLogFactory, WriterContext,
35+
ProcessStatus, ProcessorState, ProcessorTransactionLog, ProcessorTransactionLogFactory,
36+
WriterContext,
3637
},
3738
saver::AssetSaver,
3839
tests::{run_app_until, CoolText, CoolTextLoader, CoolTextRon, SubText},
@@ -1924,3 +1925,268 @@ fn asset_processor_can_write_multiple_files() {
19241925
)"#
19251926
);
19261927
}
1928+
1929+
#[test]
1930+
fn error_on_no_writer() {
1931+
let AppWithProcessor {
1932+
mut app,
1933+
source_gate,
1934+
default_source_dirs: ProcessingDirs {
1935+
source: source_dir, ..
1936+
},
1937+
..
1938+
} = create_app_with_asset_processor(&[]);
1939+
1940+
struct NoWriterProcess;
1941+
1942+
impl Process for NoWriterProcess {
1943+
type Settings = ();
1944+
1945+
async fn process(
1946+
&self,
1947+
_: &mut ProcessContext<'_>,
1948+
_: AssetMeta<(), Self>,
1949+
_: WriterContext<'_>,
1950+
) -> Result<(), ProcessError> {
1951+
// Don't start a writer!
1952+
Ok(())
1953+
}
1954+
}
1955+
1956+
app.register_asset_processor(NoWriterProcess)
1957+
.set_default_asset_processor::<NoWriterProcess>("txt");
1958+
1959+
let guard = source_gate.write_blocking();
1960+
source_dir.insert_asset_text(Path::new("whatever.txt"), "");
1961+
1962+
run_app_until_finished_processing(&mut app, guard);
1963+
1964+
let process_status = bevy_tasks::block_on(
1965+
app.world()
1966+
.resource::<AssetProcessor>()
1967+
.data()
1968+
.wait_until_processed("whatever.txt".into()),
1969+
);
1970+
// The process failed due to not having a writer.
1971+
assert_eq!(process_status, ProcessStatus::Failed);
1972+
}
1973+
1974+
#[test]
1975+
fn error_on_unfinished_writer() {
1976+
let AppWithProcessor {
1977+
mut app,
1978+
source_gate,
1979+
default_source_dirs: ProcessingDirs {
1980+
source: source_dir, ..
1981+
},
1982+
..
1983+
} = create_app_with_asset_processor(&[]);
1984+
1985+
struct UnfinishedWriterProcess;
1986+
1987+
impl Process for UnfinishedWriterProcess {
1988+
type Settings = ();
1989+
1990+
async fn process(
1991+
&self,
1992+
_: &mut ProcessContext<'_>,
1993+
_: AssetMeta<(), Self>,
1994+
writer_context: WriterContext<'_>,
1995+
) -> Result<(), ProcessError> {
1996+
let _writer = writer_context.write_single().await?;
1997+
// Don't call finish on the writer!
1998+
Ok(())
1999+
}
2000+
}
2001+
2002+
app.register_asset_processor(UnfinishedWriterProcess)
2003+
.set_default_asset_processor::<UnfinishedWriterProcess>("txt");
2004+
2005+
let guard = source_gate.write_blocking();
2006+
source_dir.insert_asset_text(Path::new("whatever.txt"), "");
2007+
2008+
run_app_until_finished_processing(&mut app, guard);
2009+
2010+
let process_status = bevy_tasks::block_on(
2011+
app.world()
2012+
.resource::<AssetProcessor>()
2013+
.data()
2014+
.wait_until_processed("whatever.txt".into()),
2015+
);
2016+
// The process failed due to having a writer that we didn't await finish on.
2017+
assert_eq!(process_status, ProcessStatus::Failed);
2018+
}
2019+
2020+
#[test]
2021+
fn error_on_single_writer_after_multiple_writer() {
2022+
let AppWithProcessor {
2023+
mut app,
2024+
source_gate,
2025+
default_source_dirs: ProcessingDirs {
2026+
source: source_dir, ..
2027+
},
2028+
..
2029+
} = create_app_with_asset_processor(&[]);
2030+
2031+
struct SingleAfterMultipleWriterProcess;
2032+
2033+
impl Process for SingleAfterMultipleWriterProcess {
2034+
type Settings = ();
2035+
2036+
async fn process(
2037+
&self,
2038+
_: &mut ProcessContext<'_>,
2039+
_: AssetMeta<(), Self>,
2040+
writer_context: WriterContext<'_>,
2041+
) -> Result<(), ProcessError> {
2042+
// Properly write a "multiple".
2043+
let writer = writer_context
2044+
.write_multiple(Path::new("multi.txt"))
2045+
.await?;
2046+
writer.finish::<CoolTextLoader>(()).await?;
2047+
2048+
// Now trying writing "single", which conflicts!
2049+
let writer = writer_context.write_single().await?;
2050+
writer.finish::<CoolTextLoader>(()).await?;
2051+
2052+
Ok(())
2053+
}
2054+
}
2055+
2056+
app.register_asset_processor(SingleAfterMultipleWriterProcess)
2057+
.set_default_asset_processor::<SingleAfterMultipleWriterProcess>("txt");
2058+
2059+
let guard = source_gate.write_blocking();
2060+
source_dir.insert_asset_text(Path::new("whatever.txt"), "");
2061+
2062+
run_app_until_finished_processing(&mut app, guard);
2063+
2064+
let process_status = bevy_tasks::block_on(
2065+
app.world()
2066+
.resource::<AssetProcessor>()
2067+
.data()
2068+
.wait_until_processed("whatever.txt".into()),
2069+
);
2070+
// The process failed due to having a single writer after a multiple writer.
2071+
assert_eq!(process_status, ProcessStatus::Failed);
2072+
}
2073+
2074+
#[test]
2075+
fn processor_can_parallelize_multiple_writes() {
2076+
let AppWithProcessor {
2077+
mut app,
2078+
source_gate,
2079+
default_source_dirs:
2080+
ProcessingDirs {
2081+
source: source_dir,
2082+
processed: processed_dir,
2083+
..
2084+
},
2085+
..
2086+
} = create_app_with_asset_processor(&[]);
2087+
2088+
struct ParallelizedWriterProcess;
2089+
2090+
impl Process for ParallelizedWriterProcess {
2091+
type Settings = ();
2092+
2093+
async fn process(
2094+
&self,
2095+
_: &mut ProcessContext<'_>,
2096+
_: AssetMeta<(), Self>,
2097+
writer_context: WriterContext<'_>,
2098+
) -> Result<(), ProcessError> {
2099+
let mut writer_1 = writer_context.write_multiple(Path::new("a.txt")).await?;
2100+
let mut writer_2 = writer_context.write_multiple(Path::new("b.txt")).await?;
2101+
2102+
// Note: this call is blocking, so it's undesirable in production code using
2103+
// single-threaded mode (e.g., platforms like Wasm). For this test though, it's not a
2104+
// big deal.
2105+
bevy_tasks::IoTaskPool::get().scope(|scope| {
2106+
scope.spawn(async {
2107+
writer_1.write_all(b"abc123").await.unwrap();
2108+
writer_1.finish::<CoolTextLoader>(()).await.unwrap();
2109+
});
2110+
scope.spawn(async {
2111+
writer_2.write_all(b"def456").await.unwrap();
2112+
writer_2.finish::<CoolTextLoader>(()).await.unwrap();
2113+
});
2114+
});
2115+
2116+
Ok(())
2117+
}
2118+
}
2119+
2120+
app.register_asset_processor(ParallelizedWriterProcess)
2121+
.set_default_asset_processor::<ParallelizedWriterProcess>("txt");
2122+
2123+
let guard = source_gate.write_blocking();
2124+
source_dir.insert_asset_text(Path::new("whatever.txt"), "");
2125+
2126+
run_app_until_finished_processing(&mut app, guard);
2127+
2128+
assert_eq!(
2129+
&read_asset_as_string(&processed_dir, Path::new("whatever.txt/a.txt")),
2130+
"abc123"
2131+
);
2132+
assert_eq!(
2133+
&read_asset_as_string(&processed_dir, Path::new("whatever.txt/b.txt")),
2134+
"def456"
2135+
);
2136+
}
2137+
2138+
#[test]
2139+
fn error_on_two_multiple_writes_for_same_path() {
2140+
let AppWithProcessor {
2141+
mut app,
2142+
source_gate,
2143+
default_source_dirs: ProcessingDirs {
2144+
source: source_dir, ..
2145+
},
2146+
..
2147+
} = create_app_with_asset_processor(&[]);
2148+
2149+
struct TwoMultipleWritesForSamePathProcess;
2150+
2151+
impl Process for TwoMultipleWritesForSamePathProcess {
2152+
type Settings = ();
2153+
2154+
async fn process(
2155+
&self,
2156+
_: &mut ProcessContext<'_>,
2157+
_: AssetMeta<(), Self>,
2158+
writer_context: WriterContext<'_>,
2159+
) -> Result<(), ProcessError> {
2160+
// Properly write a "multiple".
2161+
let writer = writer_context
2162+
.write_multiple(Path::new("multi.txt"))
2163+
.await?;
2164+
writer.finish::<CoolTextLoader>(()).await?;
2165+
2166+
// Properly write to the same "multiple".
2167+
let writer = writer_context
2168+
.write_multiple(Path::new("multi.txt"))
2169+
.await?;
2170+
writer.finish::<CoolTextLoader>(()).await?;
2171+
2172+
Ok(())
2173+
}
2174+
}
2175+
2176+
app.register_asset_processor(TwoMultipleWritesForSamePathProcess)
2177+
.set_default_asset_processor::<TwoMultipleWritesForSamePathProcess>("txt");
2178+
2179+
let guard = source_gate.write_blocking();
2180+
source_dir.insert_asset_text(Path::new("whatever.txt"), "");
2181+
2182+
run_app_until_finished_processing(&mut app, guard);
2183+
2184+
let process_status = bevy_tasks::block_on(
2185+
app.world()
2186+
.resource::<AssetProcessor>()
2187+
.data()
2188+
.wait_until_processed("whatever.txt".into()),
2189+
);
2190+
// The process failed due to writing "multiple" to the same path twice.
2191+
assert_eq!(process_status, ProcessStatus::Failed);
2192+
}

0 commit comments

Comments
 (0)