Trying to make Mac CI fail gracefully

This message may be repeated multiple times as I work on the CI
configuration.

Refs #129
This commit is contained in:
Jonathan Johnson 2024-01-08 09:17:03 -08:00
parent 5556d2ea6d
commit d7fde0815f
No known key found for this signature in database
GPG key ID: A66D6A34D6620579
5 changed files with 96 additions and 33 deletions

View file

@ -45,4 +45,11 @@ jobs:
# fixed purely by updating the rust version.
if: matrix.version == 'stable'
run: |
cargo test --all-features --all-targets
cargo test --all-features --all-targets -- --nocapture
env:
# When running on Mac OS CI, it's pretty common to not get an adapter
# returned. We don't want errors specifically caused by not being able
# to create a wgpu Adapter to cause unit test failures on CI. Long
# term it would be nice to have a reliable way to run Mac CI with a
# GPU adapter available.
NO_ADAPTER: ${{ matris.os == "macos-stable" && "github-ci" || "" }}

View file

@ -2,35 +2,33 @@ use std::time::Duration;
use cushy::animation::easings::EaseInOutSine;
use cushy::widget::MakeWidget;
use cushy::window::VirtualRecorderError;
use figures::units::Px;
use figures::{Point, Size};
#[macro_use]
mod shared;
fn ui() -> impl MakeWidget {
"Hello World".into_button().centered()
}
fn main() {
let mut recorder = ui()
.build_recorder()
.size(Size::new(320, 240))
.finish()
.unwrap();
fn main() -> Result<(), VirtualRecorderError> {
let mut recorder = ui().build_recorder().size(Size::new(320, 240)).finish()?;
let initial_point = Point::new(Px::new(140), Px::new(150));
recorder.set_cursor_position(initial_point);
recorder.set_cursor_visible(true);
recorder.refresh().unwrap();
recorder.refresh()?;
let mut animation = recorder.record_animated_png(60);
animation
.animate_cursor_to(
Point::new(Px::new(160), Px::new(120)),
Duration::from_millis(250),
EaseInOutSine,
)
.unwrap();
animation.wait_for(Duration::from_millis(500)).unwrap();
animation
.animate_cursor_to(initial_point, Duration::from_millis(250), EaseInOutSine)
.unwrap();
animation.wait_for(Duration::from_millis(500)).unwrap();
animation.write_to("examples/offscreen-apng.png").unwrap();
animation.animate_cursor_to(
Point::new(Px::new(160), Px::new(120)),
Duration::from_millis(250),
EaseInOutSine,
)?;
animation.wait_for(Duration::from_millis(500))?;
animation.animate_cursor_to(initial_point, Duration::from_millis(250), EaseInOutSine)?;
animation.wait_for(Duration::from_millis(500))?;
animation.write_to("examples/offscreen-apng.png")
}
adapter_required_test!(main);

View file

@ -1,17 +1,17 @@
use cushy::widget::MakeWidget;
use cushy::window::VirtualRecorderError;
use figures::Size;
#[macro_use]
mod shared;
fn ui() -> impl MakeWidget {
"Hello World".into_button().centered()
}
fn main() {
fn main() -> Result<(), VirtualRecorderError> {
// The default recorder generated solid, rgb images.
let recorder = ui()
.build_recorder()
.size(Size::new(320, 240))
.finish()
.unwrap();
let recorder = ui().build_recorder().size(Size::new(320, 240)).finish()?;
recorder.image().save("examples/offscreen.png").unwrap();
// Creating a recorder with alpha makes the virtual window transparent.
@ -19,12 +19,9 @@ fn main() {
.build_recorder()
.with_alpha()
.size(Size::new(320, 240))
.finish()
.unwrap();
.finish()?;
recorder.image().save("examples/offscreen.png").unwrap();
Ok(())
}
#[test]
fn runs() {
main();
}
adapter_required_test!(main);

39
examples/shared/mod.rs Normal file
View file

@ -0,0 +1,39 @@
/// This macro creates a unit test that calls the named function, and
/// potentially ignores a `NoAdapter` error.
///
/// # Background
///
/// On GitHub CI, it seems fairly common for the MacOS runners to be configured
/// in such a way that wgpu returns no adapters from a request with the default
/// settings. The default settings appear to imply as high of flexibility as
/// possible, and sometimes the runners succeed in returning an adapter.
///
/// Because of these spurious failures, this macro checks for the environment
/// variable `NO_ADAPTER`. If it is set to a value, a warning will be printed
/// instead of panicking.
#[macro_export]
macro_rules! adapter_required_test {
($name:ident) => {
#[test]
fn runs() {
let no_adapter_setting = std::env::var("NO_ADAPTER");
match ($name(), no_adapter_setting) {
(Ok(()), _) => {}
(Err(cushy::window::VirtualRecorderError::NoAdapter), Ok(no_adapter))
if !no_adapter.is_empty() =>
{
let prefix = match no_adapter.as_ref() {
"github-ci" => "::warning::",
_ => "",
};
println!(
"{prefix}Ignoring {}:{}: no graphics adapters available",
file!(),
stringify!($name)
);
}
(Err(err), _) => unreachable!("Error testing example: {err}"),
}
}
};
}

View file

@ -3607,6 +3607,28 @@ impl From<io::Error> for VirtualRecorderError {
}
}
impl std::fmt::Display for VirtualRecorderError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
VirtualRecorderError::NoAdapter => {
f.write_str("no compatible graphics adapters were found")
}
VirtualRecorderError::RequestDevice(err) => {
write!(f, "error requesting graphics device: {err}")
}
VirtualRecorderError::TooLarge => {
f.write_str("the rendered surface is too large for this cpu architecture")
}
VirtualRecorderError::MapBuffer(err) => {
write!(f, "error reading rendered graphics data: {err}")
}
VirtualRecorderError::PngEncode(err) => write!(f, "error encoding png: {err}"),
}
}
}
impl std::error::Error for VirtualRecorderError {}
/// A unique identifier of an input device.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum DeviceId {