Skip to content

For discussion: A way of improving regression/integration testing for ASL snippets#269

Merged
IsaacWoods merged 8 commits intorust-osdev:mainfrom
martin-hughes:possible-test-infra
Mar 14, 2026
Merged

For discussion: A way of improving regression/integration testing for ASL snippets#269
IsaacWoods merged 8 commits intorust-osdev:mainfrom
martin-hughes:possible-test-infra

Conversation

@martin-hughes
Copy link
Contributor

This PR is very much a proof of concept for improving testing of how ASL snippets are handled. It provides a black-box testing rig for ASL scripts that checks acpi calls the handler with the correct commands and values.

I don't really think it's ready for merging, it's mostly for comment / discussion at this time.

This idea came about because I was struggling to see what was happening with Store commands, and I see that there's only limited regression testing in general

aml_tester is useful for what it does, but it obviously doesn't let you check that the outputs from acpi are what you'd expect - only that the parser can handle the script somehow.

In terms of design notes, I included the ASL snippets in rust files for a few reasons:

  • It keeps the inputs (ASL) and outputs (expected ACPI Handler calls) in one file - for ease of maintenance
  • The expected outputs can be written in Rust and checked by the IDE
  • This design plays nicely with cargo test and/or IDE testing functionality (no need for cargo run_tests)

I spent some time wondering if the tests would be too brittle - but I think the Handler interface is not likely to change too often, and my feeling is that it's unlikely that changes to the parser would cause big changes to the sequence of Handler calls.

Thoughts anyone?

tests/basic.rs Outdated
mod test_infra;

#[test]
#[ignore]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore this test for now and concentrate on the next one.

tests/basic.rs Outdated
test_infra::run_aml_test(AML, handler);
}

#[test]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test demonstrates the kind of style I was thinking of

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is basically a cut-paste of functions from main.rs that are useful in my new test system. This clearly isn't very neat, probably best to extract to a small asl_testing crate or similar.

@IsaacWoods
Copy link
Member

I'm a big fan of this idea in general, and quite like the approach you've taken here! It was always my intention to have regression testing along these lines at some point, but I never got around to building it out, so thanks for working on this.

I guess the only downside to keeping the ASL inline with the test is a lack of syntax highlighting for those who have it set up. That's probably not the biggest loss with small snippets like most of these tests are likely to be I guess.

I'm not sure what I think about the overall library layout; I think we could likely have a neater approach by separating the compilation of the ASL and testing into a little library and then use it from a Rust-based regression test-suite and also a command-line tool for compiling and running a provided blob (which is still useful for eg testing some hardware's extracted tables). I think that might be what you're already suggesting? In which case definitely green light on that.

pci_types = { version = "0.10.0", public = true }
byteorder = { version = "1.5.0", default-features = false }

[dev-dependencies]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be mistaken but do these need to be dev-dependencies on the top-level acpi crate? Or dependencies on the aml_test_tools crate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dependencies on the sub-crate almost certainly. I'll flesh it out and update the PR.

tests/basic.rs Outdated
test_infra::run_aml_test(AML, handler);
}

#[test]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!


pub type Command = (Check, Response);

pub fn construct_std_handler(commands: Vec<Command>) -> impl Handler {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the concept of "stacking" handlers but wonder if there is utility in separating checking for actions in the right order and what the handlers responses should be? I feel a single handler that does both might be easier to understand.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I spent a bit of time wondering about this before writing it. The example I thought of is that I might want to write a handler that stores all the writes (e.g. in a map of IO ports -> written value) and then reads them back on the relevant read. Which might be useful for longer or more complex tests. We might still want to check which handler functions are called but with this new innards (i.e. the constructor call would be CheckCommandHandler::new(c, StoredResponsesHandler::new(r)) or similar)

Plus SRP, although I might have gone a bit overboard in this case 😆

If you're not a fan just pop a comment here and I'll merge them into one handler.

}

fn check_command(&self, command: AcpiCommands) {
let next_command_idx = self.next_command_idx.load(Relaxed);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't matter in this case really, but for correctness I feel this should do the fetch_add here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good shout.

@martin-hughes
Copy link
Contributor Author

Thanks for taking a look @IsaacWoods 😊 I'll work on it some more and post an update when I can.

I guess the only downside to keeping the ASL inline with the test is a lack of syntax highlighting for those who have it set up. That's probably not the biggest loss with small snippets like most of these tests are likely to be I guess.

Interesting point that I hadn't thought of... I agree that most snippets should be pretty simple. The only mitigation I can think of for longer scripts would be to use include_str! to include more complex ASL files directly. This might actually suit well - longer snippets would make it harder to explore the tests anyway.

I think that might be what you're already suggesting? In which case definitely green light on that.

Pretty much, yes - just laziness had prevailed for this first draft 😆.

Cheers again.

@martin-hughes
Copy link
Contributor Author

Updated as above, except I haven't merged the check/response handlers - do you want me to, or was my explanation OK?

The only dev-dependencies left on the main crate are the ones used by the tests themselves.

Ready for another look @IsaacWoods 😊

@martin-hughes martin-hughes marked this pull request as ready for review March 9, 2026 15:05
Having to create `Check` and `Response` items for each test is a bit
laborious, so this simplifies things whilst keeping the SRP-ness of the
two Handlers / allowing for future flexibility.
@martin-hughes
Copy link
Contributor Author

I've made a few ergonomic improvements this morning that reduce the burden to the end user of using the standard test handler, whilst keeping the flexibility to easily add other handlers/combinations of handlers in future.

let output_name = format!("{}.aml", output_stem);
let output_full_name = dir.path().join(output_name.clone());

let new_asl = asl.replace("%FN%", output_name.as_str());
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only just realised you don't need to specify a filename as the first parameter of DefinitionBlock 🤦. Want me to strip this feature out?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, does iasl infer the correct filename for the result if not provided? If that works consistently then I have no issue utilising it, but possible it differs on iasl version or something - no strong feelings either way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question - it seems to always infer it, but I guess it could change without warning. I see you left it in, and I think that would probably have been my preference in the end anyway.

Cheers for your comments on this whole PR!

@IsaacWoods
Copy link
Member

IsaacWoods commented Mar 14, 2026

This is really fantastic work, thanks @martin-hughes!
This looks like it'll be useful for my next steps of working out our semantics woes re references (will get back to you on your related issues shortly) so let's get this merged here, and we can work out details re multiple tests in future PRs.

Cheers!

--- Edit ---
Your reasoning on the split handlers makes sense - I can see future use for e.g. recording a problematic firmwares responses somehow and utilising a sort-of replay handler or better modelling of I/O ports or a PCIe bus if we want to get fancier. Thanks.

@IsaacWoods IsaacWoods merged commit 21e8039 into rust-osdev:main Mar 14, 2026
5 checks passed
@martin-hughes martin-hughes deleted the possible-test-infra branch March 14, 2026 21:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants