-
Notifications
You must be signed in to change notification settings - Fork 611
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[cmd] Add and use CommandScheduler.resetInstance() #7584
base: main
Are you sure you want to change the base?
[cmd] Add and use CommandScheduler.resetInstance() #7584
Conversation
This PR modifies commands. Please open a corresponding PR in Python Commands and include a link to this PR. |
Already done in Python (see link in PR comment). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there any tests that don't inherit from CommandTestBase etc?
* Resets the Scheduler instance, which is useful for testing purposes. This should not be called | ||
* from user code. | ||
*/ | ||
public static synchronized void resetInstance() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest it should null-op with a warning on a real robot. Is there a reason not to avoid the risk of a team accidentally resetting the scheduler in the middle of a match?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds like a good idea- How could we detect we're running on a real robot versus in tests? I'd assume we wouldn't want to use isFMSAttached()
because then it might lead to code working in the lab but not in an actual match, which would really suck.
I guess the way to really really avoid sneaky behavior changes is to always check (somehow) whether the call is from robot code (and not test code), but that's going to be really tricky for C++.
Another silly thought I had is to have a string parameter that must be "This method should only be called in unit tests. I promise I am not abusing this inside robot code." for the method to work, but that's not the most professional solution. (It would be pretty easy and funny, though.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isReal()
/isSimulation()
?
@@ -93,6 +93,10 @@ CommandScheduler& CommandScheduler::GetInstance() { | |||
return scheduler; | |||
} | |||
|
|||
void CommandScheduler::ResetInstance() { | |||
std::make_unique<Impl>().swap(GetInstance().m_impl); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto
I think the safest bet here might be a "scope function" of sorts. Such as:
The advantage here i think is that when the scope is done executing, the default CommandScheduler instance can be reinstated, preventing sneaky errors from occuring. All of the test can occur within the scope block |
Thanks for the suggestions, everyone! I've thought about a few different options, and I'm not completely sure which one to go for. Option C is mostly just for fun- While writing this out, I realized that it doesn't really have any advantages over the other options. Option A:
Option B:
Option C: Context manager
|
Either way I think too much stuff reaches into the scheduler statically to have swapping out the scheduler be clean. As for C, a separate type isn't needed -- CommandScheduler already implements AutoCloseable (and parallels); it's just that implementation is focused on the Sendable implementation. Having the close() method reset the state would be quite clean. Whether it swaps the instance or just resets the same one is up for discussion (I'm leaning towards the former) |
Lol i actually wasnt designing it for this purpose, just thought that it would be a good idea to have some cleanup available at the end. Honestly though I prefer the try with resources method now that u bring it up. |
Ended up going with
Yes, it would- I didn't explain the idea behind C much, but the idea was to have a separate context-manager/try-with-resources type that would on creation swap out the command scheduler implementation and on destruction swap it back. I didn't want to put the scope management in the CommandScheduler class because then we would need to let users make a new instance in some way to use the scope management, which could cause issues because then people could use a command scheduler instance that isn't the same one used by |
Also makes the constructor private, since it was only used for the tests which now can use
resetInstance()
. Technically a breaking change for people putting their command unit tests in the commands package, but I doubt that many people would do that.Closes #4866.
Python already has
resetInstance()
: https://github.com/robotpy/robotpy-commands-v2/blob/8480f6e3e3a5877e9489300ab8c5ec81703f2ad7/commands2/commandscheduler.py#L54.Most of the changes are just removing
try (CommandScheduler scheduler = new CommandScheduler()) {}
, but there's a few other changes to the tests:SchedulerTest.registerSubsystem()
andSchedulerTest.unregisterSubsystem()
were both changed to useSubsystem
instead ofSubsystemBase
sinceSubsystemBase
would automatically register the subsystem with the singleton instance.this
(which is by reference) since that's where the scheduler is stored now.CommandRequirementsTest.RequirementInterrupt
andSchedulerTest.SchedulerInterruptLambdaCause
had to be changed in C++ because the command deconstructors canceled the command at the end of their scope.