terminal/src/cascadia/UnitTests_Remoting/RemotingTests.cpp

1356 lines
57 KiB
C++
Raw Normal View History

Add `Microsoft.Terminal.Remoting.dll` (#8607) Adds a `Microsoft.Terminal.Remoting.dll` to our solution. This DLL will be responsible for all the Monarch/Peasant work that's been described in #7240 & #8135. This PR does _not_ implement the Monarch/Peasant architecture in any significant way. The goal of this PR is to just to establish the project layout, and the most basic connections. This should make reviewing the actual meat of the implementation (in a later PR) easier. It will also give us the opportunity to include some of the basic weird things we're doing (with `CoRegisterClass`) in the Terminal _now_, and get them selfhosted, before building on them too much. This PR does have windows registering the `Monarch` class with COM. When windows are created, they'll as the Monarch if they should create a new window or not. In this PR, the Monarch will always reply "yes, please make a new window". Similar to other projects in our solution, we're adding 3 projects here: * `Microsoft.Terminal.Remoting.lib`: the actual implementation, as a static lib. * `Microsoft.Terminal.Remoting.dll`: The implementation linked as a DLL, for use in `WindowsTerminal.exe`. * `Remoting.UnitTests.dll`: A unit test dll that links with the static lib. There are plenty of TODOs scattered about the code. Clearly, most of this isn't implemented yet, but I do have more WIP branches. I'm using [`projects/5`](https://github.com/microsoft/terminal/projects/5) as my notation for TODOs that are too small for an issue, but are part of the whole Process Model 2.0 work. ## References * #5000 - this is the process model megathread * #7240 - The process model 2.0 spec. * #8135 - the window management spec. (please review me, I have 0/3 signoffs even after the discussion we had 😢) * #8171 - the Monarch/peasant sample. (please review me, I have 1/2) ## PR Checklist * [x] Closes nothing, this is just infrastructure * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated
2021-01-07 23:59:37 +01:00
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "../Remoting/Monarch.h"
Add support for running a commandline in another WT window (#8898) ## Summary of the Pull Request **If you're reading this PR and haven't signed off on #8135, go there first.** ![window-management-000](https://user-images.githubusercontent.com/18356694/103932910-25199380-50e8-11eb-97e3-594a31da62d2.gif) This provides the basic parts of the implementation of #4472. Namely: * We add support for the `--window,-w <window-id>` argument to `wt.exe`, to allow a commandline to be given to another window. * If `window-id` is `0`, run the given commands in _the current window_. * If `window-id` is a negative number, run the commands in a _new_ Terminal window. * If `window-id` is the ID of an existing window, then run the commandline in that window. * If `window-id` is _not_ the ID of an existing window, create a new window. That window will be assigned the ID provided in the commandline. The provided subcommands will be run in that new window. * If `window-id` is omitted, then create a new window. ## References * Spec: #8135 * Megathread: #5000 * Project: projects/5 ## PR Checklist * [x] Closes #4472 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - **sure does** ## Detailed Description of the Pull Request / Additional comments Note that `wt -w 1 -d c:\foo cmd.exe` does work, by causing window 1 to change There are limitations, and there are plenty of things to work on in the future: * [ ] We don't support names for windows yet * [ ] We don't support window glomming by default, or a setting to configure what happens when `-w` is omitted. I thought it best to lay the groundwork first, then come back to that. * [ ] `-w 0` currently just uses the "last activated" window, not "the current". There's more follow-up work to try and smartly find the actual window we're being called from. * [ ] Basically anything else that's listed in projects/5. I'm cutting this PR where it currently is, because this is already a huge PR. I believe the remaining tasks will all be easier to land, once this is in. ## Validation Steps Performed I've been creating windows, and closing them, and running cmdlines for a while now. I'm gonna keep doing that while the PR is open, till no bugs remain. # TODOs * [x] There are a bunch of `GetID`, `GetPID` calls that aren't try/caught 😬 - [x] `Monarch.cpp` - [x] `Peasant.cpp` - [x] `WindowManager.cpp` - [x] `AppHost.cpp` * [x] If the monarch gets hung, then _you can't launch any Terminals_ 😨 We should handle this gracefully. - Proposed idea: give the Monarch some time to respond to a proposal for a commandline. If there's no response in that timeframe, this window is now a _hermit_, outside of society entirely. It can't be elected Monarch. It can't receive command lines. It has no ID. - Could we gracefully recover from such a state? maybe, probably not though. - Same deal if a peasant hangs, it could end up hanging the monarch, right? Like if you do `wt -w 2`, and `2` is hung, then does the monarch get hung waiting on the hung peasant? - After talking with @miniksa, **we're gonna punt this from the initial implementation**. If people legit hit this in the wild, we'll fix it then.
2021-02-10 12:28:09 +01:00
#include "../Remoting/CommandlineArgs.h"
#include "../Remoting/FindTargetWindowArgs.h"
#include "../Remoting/ProposeCommandlineResult.h"
Add support for naming windows with the `-w` parameter (#9300) This finishes the implementation of `--window` to also accept a string as the "name" of the window. So you can say ```sh wt -w foo new-tab wt -w foo split-pane ``` and have both those commands execute in the same window, the one named "foo". This is just slightly more ergonomic than manually using the IDs of windows. In the future, I'll be working on renaming windows, and displaying these names. > #### `--window,-w <window-id>` > Run these commands in the given Windows Terminal session. This enables opening > new tabs, splits, etc. in already running Windows Terminal windows. > * If `window-id` is `0`, run the given commands in _the current window_. > * If `window-id` is a negative number, or the reserved name `new`, run the > commands in a _new_ Terminal window. > * If `window-id` is the ID or name of an existing window, then run the > commandline in that window. > * If `window-id` is _not_ the ID or name of an existing window, create a new > window. That window will be assigned the ID or name provided in the > commandline. The provided subcommands will be run in that new window. > * If `window-id` is omitted, then obey the value of `windowingBehavior` when > determining which window to run the command in. Before this PR, I think we didn't actually properly support assigning the id with `wt -w 12345`. If `12345` didn't exist, it would make a new window, but just assign it the next id, not assign it 12345. ## References * #4472, #8135 * https://github.com/microsoft/terminal/projects/5 ## Validation Steps Performed Ran tests Messed with naming windows, working as expected. Closes https://github.com/microsoft/terminal/projects/5#card-51431478
2021-03-17 20:28:01 +01:00
#include "../inc/WindowingBehavior.h"
Add `Microsoft.Terminal.Remoting.dll` (#8607) Adds a `Microsoft.Terminal.Remoting.dll` to our solution. This DLL will be responsible for all the Monarch/Peasant work that's been described in #7240 & #8135. This PR does _not_ implement the Monarch/Peasant architecture in any significant way. The goal of this PR is to just to establish the project layout, and the most basic connections. This should make reviewing the actual meat of the implementation (in a later PR) easier. It will also give us the opportunity to include some of the basic weird things we're doing (with `CoRegisterClass`) in the Terminal _now_, and get them selfhosted, before building on them too much. This PR does have windows registering the `Monarch` class with COM. When windows are created, they'll as the Monarch if they should create a new window or not. In this PR, the Monarch will always reply "yes, please make a new window". Similar to other projects in our solution, we're adding 3 projects here: * `Microsoft.Terminal.Remoting.lib`: the actual implementation, as a static lib. * `Microsoft.Terminal.Remoting.dll`: The implementation linked as a DLL, for use in `WindowsTerminal.exe`. * `Remoting.UnitTests.dll`: A unit test dll that links with the static lib. There are plenty of TODOs scattered about the code. Clearly, most of this isn't implemented yet, but I do have more WIP branches. I'm using [`projects/5`](https://github.com/microsoft/terminal/projects/5) as my notation for TODOs that are too small for an issue, but are part of the whole Process Model 2.0 work. ## References * #5000 - this is the process model megathread * #7240 - The process model 2.0 spec. * #8135 - the window management spec. (please review me, I have 0/3 signoffs even after the discussion we had 😢) * #8171 - the Monarch/peasant sample. (please review me, I have 1/2) ## PR Checklist * [x] Closes nothing, this is just infrastructure * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated
2021-01-07 23:59:37 +01:00
using namespace Microsoft::Console;
using namespace WEX::Logging;
using namespace WEX::TestExecution;
using namespace WEX::Common;
using namespace winrt;
using namespace winrt::Microsoft::Terminal;
// These are some gross macros that let us call a private ctor for
// Monarch/Peasant. We can't just use make_self, because that doesn't let us
// call a private ctor. We can use com_ptr::attach, but since we're allocating
// the thing on the stack, we need to make sure to call detach before the object
// is destructed.
#define MAKE_MONARCH(name, pid) \
Remoting::implementation::Monarch _local_##name##{ pid }; \
com_ptr<Remoting::implementation::Monarch> name; \
name.attach(&_local_##name##); \
auto cleanup_##name## = wil::scope_exit([&]() { name.detach(); });
#define MAKE_PEASANT(name, pid) \
Remoting::implementation::Peasant _local_##name##{ pid }; \
com_ptr<Remoting::implementation::Peasant> name; \
name.attach(&_local_##name##); \
auto cleanup_##name## = wil::scope_exit([&]() { name.detach(); });
namespace RemotingUnitTests
{
Add support for running a commandline in another WT window (#8898) ## Summary of the Pull Request **If you're reading this PR and haven't signed off on #8135, go there first.** ![window-management-000](https://user-images.githubusercontent.com/18356694/103932910-25199380-50e8-11eb-97e3-594a31da62d2.gif) This provides the basic parts of the implementation of #4472. Namely: * We add support for the `--window,-w <window-id>` argument to `wt.exe`, to allow a commandline to be given to another window. * If `window-id` is `0`, run the given commands in _the current window_. * If `window-id` is a negative number, run the commands in a _new_ Terminal window. * If `window-id` is the ID of an existing window, then run the commandline in that window. * If `window-id` is _not_ the ID of an existing window, create a new window. That window will be assigned the ID provided in the commandline. The provided subcommands will be run in that new window. * If `window-id` is omitted, then create a new window. ## References * Spec: #8135 * Megathread: #5000 * Project: projects/5 ## PR Checklist * [x] Closes #4472 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - **sure does** ## Detailed Description of the Pull Request / Additional comments Note that `wt -w 1 -d c:\foo cmd.exe` does work, by causing window 1 to change There are limitations, and there are plenty of things to work on in the future: * [ ] We don't support names for windows yet * [ ] We don't support window glomming by default, or a setting to configure what happens when `-w` is omitted. I thought it best to lay the groundwork first, then come back to that. * [ ] `-w 0` currently just uses the "last activated" window, not "the current". There's more follow-up work to try and smartly find the actual window we're being called from. * [ ] Basically anything else that's listed in projects/5. I'm cutting this PR where it currently is, because this is already a huge PR. I believe the remaining tasks will all be easier to land, once this is in. ## Validation Steps Performed I've been creating windows, and closing them, and running cmdlines for a while now. I'm gonna keep doing that while the PR is open, till no bugs remain. # TODOs * [x] There are a bunch of `GetID`, `GetPID` calls that aren't try/caught 😬 - [x] `Monarch.cpp` - [x] `Peasant.cpp` - [x] `WindowManager.cpp` - [x] `AppHost.cpp` * [x] If the monarch gets hung, then _you can't launch any Terminals_ 😨 We should handle this gracefully. - Proposed idea: give the Monarch some time to respond to a proposal for a commandline. If there's no response in that timeframe, this window is now a _hermit_, outside of society entirely. It can't be elected Monarch. It can't receive command lines. It has no ID. - Could we gracefully recover from such a state? maybe, probably not though. - Same deal if a peasant hangs, it could end up hanging the monarch, right? Like if you do `wt -w 2`, and `2` is hung, then does the monarch get hung waiting on the hung peasant? - After talking with @miniksa, **we're gonna punt this from the initial implementation**. If people legit hit this in the wild, we'll fix it then.
2021-02-10 12:28:09 +01:00
// This is a silly helper struct.
// It will always throw an hresult_error on any of its methods.
//
// In the tests, it's hard to emulate a peasant process being totally dead
// once the Monarch has captured a reference to it. Since everything's
// in-proc in the tests, we can't decrement the refcount in such a way that
// the monarch's reference will throw a catchable exception. Instead, this
// class can be used to replace a peasant inside a Monarch, to emulate that
// peasant process dying. Any time the monarch tries to do something to this
// peasant, it'll throw an exception.
struct DeadPeasant : implements<DeadPeasant, winrt::Microsoft::Terminal::Remoting::IPeasant>
{
DeadPeasant() = default;
void AssignID(uint64_t /*id*/) { throw winrt::hresult_error{}; };
uint64_t GetID() { throw winrt::hresult_error{}; };
Add support for naming windows with the `-w` parameter (#9300) This finishes the implementation of `--window` to also accept a string as the "name" of the window. So you can say ```sh wt -w foo new-tab wt -w foo split-pane ``` and have both those commands execute in the same window, the one named "foo". This is just slightly more ergonomic than manually using the IDs of windows. In the future, I'll be working on renaming windows, and displaying these names. > #### `--window,-w <window-id>` > Run these commands in the given Windows Terminal session. This enables opening > new tabs, splits, etc. in already running Windows Terminal windows. > * If `window-id` is `0`, run the given commands in _the current window_. > * If `window-id` is a negative number, or the reserved name `new`, run the > commands in a _new_ Terminal window. > * If `window-id` is the ID or name of an existing window, then run the > commandline in that window. > * If `window-id` is _not_ the ID or name of an existing window, create a new > window. That window will be assigned the ID or name provided in the > commandline. The provided subcommands will be run in that new window. > * If `window-id` is omitted, then obey the value of `windowingBehavior` when > determining which window to run the command in. Before this PR, I think we didn't actually properly support assigning the id with `wt -w 12345`. If `12345` didn't exist, it would make a new window, but just assign it the next id, not assign it 12345. ## References * #4472, #8135 * https://github.com/microsoft/terminal/projects/5 ## Validation Steps Performed Ran tests Messed with naming windows, working as expected. Closes https://github.com/microsoft/terminal/projects/5#card-51431478
2021-03-17 20:28:01 +01:00
winrt::hstring WindowName() { throw winrt::hresult_error{}; };
Add support for running a commandline in another WT window (#8898) ## Summary of the Pull Request **If you're reading this PR and haven't signed off on #8135, go there first.** ![window-management-000](https://user-images.githubusercontent.com/18356694/103932910-25199380-50e8-11eb-97e3-594a31da62d2.gif) This provides the basic parts of the implementation of #4472. Namely: * We add support for the `--window,-w <window-id>` argument to `wt.exe`, to allow a commandline to be given to another window. * If `window-id` is `0`, run the given commands in _the current window_. * If `window-id` is a negative number, run the commands in a _new_ Terminal window. * If `window-id` is the ID of an existing window, then run the commandline in that window. * If `window-id` is _not_ the ID of an existing window, create a new window. That window will be assigned the ID provided in the commandline. The provided subcommands will be run in that new window. * If `window-id` is omitted, then create a new window. ## References * Spec: #8135 * Megathread: #5000 * Project: projects/5 ## PR Checklist * [x] Closes #4472 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - **sure does** ## Detailed Description of the Pull Request / Additional comments Note that `wt -w 1 -d c:\foo cmd.exe` does work, by causing window 1 to change There are limitations, and there are plenty of things to work on in the future: * [ ] We don't support names for windows yet * [ ] We don't support window glomming by default, or a setting to configure what happens when `-w` is omitted. I thought it best to lay the groundwork first, then come back to that. * [ ] `-w 0` currently just uses the "last activated" window, not "the current". There's more follow-up work to try and smartly find the actual window we're being called from. * [ ] Basically anything else that's listed in projects/5. I'm cutting this PR where it currently is, because this is already a huge PR. I believe the remaining tasks will all be easier to land, once this is in. ## Validation Steps Performed I've been creating windows, and closing them, and running cmdlines for a while now. I'm gonna keep doing that while the PR is open, till no bugs remain. # TODOs * [x] There are a bunch of `GetID`, `GetPID` calls that aren't try/caught 😬 - [x] `Monarch.cpp` - [x] `Peasant.cpp` - [x] `WindowManager.cpp` - [x] `AppHost.cpp` * [x] If the monarch gets hung, then _you can't launch any Terminals_ 😨 We should handle this gracefully. - Proposed idea: give the Monarch some time to respond to a proposal for a commandline. If there's no response in that timeframe, this window is now a _hermit_, outside of society entirely. It can't be elected Monarch. It can't receive command lines. It has no ID. - Could we gracefully recover from such a state? maybe, probably not though. - Same deal if a peasant hangs, it could end up hanging the monarch, right? Like if you do `wt -w 2`, and `2` is hung, then does the monarch get hung waiting on the hung peasant? - After talking with @miniksa, **we're gonna punt this from the initial implementation**. If people legit hit this in the wild, we'll fix it then.
2021-02-10 12:28:09 +01:00
uint64_t GetPID() { throw winrt::hresult_error{}; };
bool ExecuteCommandline(const Remoting::CommandlineArgs& /*args*/) { throw winrt::hresult_error{}; }
void ActivateWindow(const Remoting::WindowActivatedArgs& /*args*/) { throw winrt::hresult_error{}; }
Remoting::CommandlineArgs InitialArgs() { throw winrt::hresult_error{}; }
Remoting::WindowActivatedArgs GetLastActivatedArgs() { throw winrt::hresult_error{}; }
TYPED_EVENT(WindowActivated, winrt::Windows::Foundation::IInspectable, Remoting::WindowActivatedArgs);
TYPED_EVENT(ExecuteCommandlineRequested, winrt::Windows::Foundation::IInspectable, Remoting::CommandlineArgs);
};
Add `Microsoft.Terminal.Remoting.dll` (#8607) Adds a `Microsoft.Terminal.Remoting.dll` to our solution. This DLL will be responsible for all the Monarch/Peasant work that's been described in #7240 & #8135. This PR does _not_ implement the Monarch/Peasant architecture in any significant way. The goal of this PR is to just to establish the project layout, and the most basic connections. This should make reviewing the actual meat of the implementation (in a later PR) easier. It will also give us the opportunity to include some of the basic weird things we're doing (with `CoRegisterClass`) in the Terminal _now_, and get them selfhosted, before building on them too much. This PR does have windows registering the `Monarch` class with COM. When windows are created, they'll as the Monarch if they should create a new window or not. In this PR, the Monarch will always reply "yes, please make a new window". Similar to other projects in our solution, we're adding 3 projects here: * `Microsoft.Terminal.Remoting.lib`: the actual implementation, as a static lib. * `Microsoft.Terminal.Remoting.dll`: The implementation linked as a DLL, for use in `WindowsTerminal.exe`. * `Remoting.UnitTests.dll`: A unit test dll that links with the static lib. There are plenty of TODOs scattered about the code. Clearly, most of this isn't implemented yet, but I do have more WIP branches. I'm using [`projects/5`](https://github.com/microsoft/terminal/projects/5) as my notation for TODOs that are too small for an issue, but are part of the whole Process Model 2.0 work. ## References * #5000 - this is the process model megathread * #7240 - The process model 2.0 spec. * #8135 - the window management spec. (please review me, I have 0/3 signoffs even after the discussion we had 😢) * #8171 - the Monarch/peasant sample. (please review me, I have 1/2) ## PR Checklist * [x] Closes nothing, this is just infrastructure * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated
2021-01-07 23:59:37 +01:00
class RemotingTests
{
BEGIN_TEST_CLASS(RemotingTests)
END_TEST_CLASS()
TEST_METHOD(CreateMonarch);
TEST_METHOD(CreatePeasant);
Add support for running a commandline in another WT window (#8898) ## Summary of the Pull Request **If you're reading this PR and haven't signed off on #8135, go there first.** ![window-management-000](https://user-images.githubusercontent.com/18356694/103932910-25199380-50e8-11eb-97e3-594a31da62d2.gif) This provides the basic parts of the implementation of #4472. Namely: * We add support for the `--window,-w <window-id>` argument to `wt.exe`, to allow a commandline to be given to another window. * If `window-id` is `0`, run the given commands in _the current window_. * If `window-id` is a negative number, run the commands in a _new_ Terminal window. * If `window-id` is the ID of an existing window, then run the commandline in that window. * If `window-id` is _not_ the ID of an existing window, create a new window. That window will be assigned the ID provided in the commandline. The provided subcommands will be run in that new window. * If `window-id` is omitted, then create a new window. ## References * Spec: #8135 * Megathread: #5000 * Project: projects/5 ## PR Checklist * [x] Closes #4472 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - **sure does** ## Detailed Description of the Pull Request / Additional comments Note that `wt -w 1 -d c:\foo cmd.exe` does work, by causing window 1 to change There are limitations, and there are plenty of things to work on in the future: * [ ] We don't support names for windows yet * [ ] We don't support window glomming by default, or a setting to configure what happens when `-w` is omitted. I thought it best to lay the groundwork first, then come back to that. * [ ] `-w 0` currently just uses the "last activated" window, not "the current". There's more follow-up work to try and smartly find the actual window we're being called from. * [ ] Basically anything else that's listed in projects/5. I'm cutting this PR where it currently is, because this is already a huge PR. I believe the remaining tasks will all be easier to land, once this is in. ## Validation Steps Performed I've been creating windows, and closing them, and running cmdlines for a while now. I'm gonna keep doing that while the PR is open, till no bugs remain. # TODOs * [x] There are a bunch of `GetID`, `GetPID` calls that aren't try/caught 😬 - [x] `Monarch.cpp` - [x] `Peasant.cpp` - [x] `WindowManager.cpp` - [x] `AppHost.cpp` * [x] If the monarch gets hung, then _you can't launch any Terminals_ 😨 We should handle this gracefully. - Proposed idea: give the Monarch some time to respond to a proposal for a commandline. If there's no response in that timeframe, this window is now a _hermit_, outside of society entirely. It can't be elected Monarch. It can't receive command lines. It has no ID. - Could we gracefully recover from such a state? maybe, probably not though. - Same deal if a peasant hangs, it could end up hanging the monarch, right? Like if you do `wt -w 2`, and `2` is hung, then does the monarch get hung waiting on the hung peasant? - After talking with @miniksa, **we're gonna punt this from the initial implementation**. If people legit hit this in the wild, we'll fix it then.
2021-02-10 12:28:09 +01:00
TEST_METHOD(CreatePeasantWithNew);
TEST_METHOD(AddPeasants);
TEST_METHOD(GetPeasantsByID);
TEST_METHOD(AddPeasantsToNewMonarch);
TEST_METHOD(RemovePeasantFromMonarchWhenFreed);
TEST_METHOD(ProposeCommandlineNoWindow);
TEST_METHOD(ProposeCommandlineGivenWindow);
TEST_METHOD(ProposeCommandlineNegativeWindow);
TEST_METHOD(ProposeCommandlineCurrentWindow);
TEST_METHOD(ProposeCommandlineNonExistentWindow);
TEST_METHOD(ProposeCommandlineDeadWindow);
Add `Microsoft.Terminal.Remoting.dll` (#8607) Adds a `Microsoft.Terminal.Remoting.dll` to our solution. This DLL will be responsible for all the Monarch/Peasant work that's been described in #7240 & #8135. This PR does _not_ implement the Monarch/Peasant architecture in any significant way. The goal of this PR is to just to establish the project layout, and the most basic connections. This should make reviewing the actual meat of the implementation (in a later PR) easier. It will also give us the opportunity to include some of the basic weird things we're doing (with `CoRegisterClass`) in the Terminal _now_, and get them selfhosted, before building on them too much. This PR does have windows registering the `Monarch` class with COM. When windows are created, they'll as the Monarch if they should create a new window or not. In this PR, the Monarch will always reply "yes, please make a new window". Similar to other projects in our solution, we're adding 3 projects here: * `Microsoft.Terminal.Remoting.lib`: the actual implementation, as a static lib. * `Microsoft.Terminal.Remoting.dll`: The implementation linked as a DLL, for use in `WindowsTerminal.exe`. * `Remoting.UnitTests.dll`: A unit test dll that links with the static lib. There are plenty of TODOs scattered about the code. Clearly, most of this isn't implemented yet, but I do have more WIP branches. I'm using [`projects/5`](https://github.com/microsoft/terminal/projects/5) as my notation for TODOs that are too small for an issue, but are part of the whole Process Model 2.0 work. ## References * #5000 - this is the process model megathread * #7240 - The process model 2.0 spec. * #8135 - the window management spec. (please review me, I have 0/3 signoffs even after the discussion we had 😢) * #8171 - the Monarch/peasant sample. (please review me, I have 1/2) ## PR Checklist * [x] Closes nothing, this is just infrastructure * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated
2021-01-07 23:59:37 +01:00
TEST_METHOD(MostRecentWindowSameDesktops);
TEST_METHOD(MostRecentWindowDifferentDesktops);
TEST_METHOD(MostRecentWindowMoveDesktops);
TEST_METHOD(GetMostRecentAnyDesktop);
TEST_METHOD(MostRecentIsDead);
Add support for naming windows with the `-w` parameter (#9300) This finishes the implementation of `--window` to also accept a string as the "name" of the window. So you can say ```sh wt -w foo new-tab wt -w foo split-pane ``` and have both those commands execute in the same window, the one named "foo". This is just slightly more ergonomic than manually using the IDs of windows. In the future, I'll be working on renaming windows, and displaying these names. > #### `--window,-w <window-id>` > Run these commands in the given Windows Terminal session. This enables opening > new tabs, splits, etc. in already running Windows Terminal windows. > * If `window-id` is `0`, run the given commands in _the current window_. > * If `window-id` is a negative number, or the reserved name `new`, run the > commands in a _new_ Terminal window. > * If `window-id` is the ID or name of an existing window, then run the > commandline in that window. > * If `window-id` is _not_ the ID or name of an existing window, create a new > window. That window will be assigned the ID or name provided in the > commandline. The provided subcommands will be run in that new window. > * If `window-id` is omitted, then obey the value of `windowingBehavior` when > determining which window to run the command in. Before this PR, I think we didn't actually properly support assigning the id with `wt -w 12345`. If `12345` didn't exist, it would make a new window, but just assign it the next id, not assign it 12345. ## References * #4472, #8135 * https://github.com/microsoft/terminal/projects/5 ## Validation Steps Performed Ran tests Messed with naming windows, working as expected. Closes https://github.com/microsoft/terminal/projects/5#card-51431478
2021-03-17 20:28:01 +01:00
TEST_METHOD(GetPeasantsByName);
TEST_METHOD(AddNamedPeasantsToNewMonarch);
TEST_METHOD(LookupNamedPeasantWhenOthersDied);
TEST_METHOD(LookupNamedPeasantWhenItDied);
TEST_METHOD(GetMruPeasantAfterNameLookupForDeadPeasant);
TEST_METHOD(ProposeCommandlineForNamedDeadWindow);
Add `Microsoft.Terminal.Remoting.dll` (#8607) Adds a `Microsoft.Terminal.Remoting.dll` to our solution. This DLL will be responsible for all the Monarch/Peasant work that's been described in #7240 & #8135. This PR does _not_ implement the Monarch/Peasant architecture in any significant way. The goal of this PR is to just to establish the project layout, and the most basic connections. This should make reviewing the actual meat of the implementation (in a later PR) easier. It will also give us the opportunity to include some of the basic weird things we're doing (with `CoRegisterClass`) in the Terminal _now_, and get them selfhosted, before building on them too much. This PR does have windows registering the `Monarch` class with COM. When windows are created, they'll as the Monarch if they should create a new window or not. In this PR, the Monarch will always reply "yes, please make a new window". Similar to other projects in our solution, we're adding 3 projects here: * `Microsoft.Terminal.Remoting.lib`: the actual implementation, as a static lib. * `Microsoft.Terminal.Remoting.dll`: The implementation linked as a DLL, for use in `WindowsTerminal.exe`. * `Remoting.UnitTests.dll`: A unit test dll that links with the static lib. There are plenty of TODOs scattered about the code. Clearly, most of this isn't implemented yet, but I do have more WIP branches. I'm using [`projects/5`](https://github.com/microsoft/terminal/projects/5) as my notation for TODOs that are too small for an issue, but are part of the whole Process Model 2.0 work. ## References * #5000 - this is the process model megathread * #7240 - The process model 2.0 spec. * #8135 - the window management spec. (please review me, I have 0/3 signoffs even after the discussion we had 😢) * #8171 - the Monarch/peasant sample. (please review me, I have 1/2) ## PR Checklist * [x] Closes nothing, this is just infrastructure * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated
2021-01-07 23:59:37 +01:00
TEST_CLASS_SETUP(ClassSetup)
{
return true;
}
Add support for running a commandline in another WT window (#8898) ## Summary of the Pull Request **If you're reading this PR and haven't signed off on #8135, go there first.** ![window-management-000](https://user-images.githubusercontent.com/18356694/103932910-25199380-50e8-11eb-97e3-594a31da62d2.gif) This provides the basic parts of the implementation of #4472. Namely: * We add support for the `--window,-w <window-id>` argument to `wt.exe`, to allow a commandline to be given to another window. * If `window-id` is `0`, run the given commands in _the current window_. * If `window-id` is a negative number, run the commands in a _new_ Terminal window. * If `window-id` is the ID of an existing window, then run the commandline in that window. * If `window-id` is _not_ the ID of an existing window, create a new window. That window will be assigned the ID provided in the commandline. The provided subcommands will be run in that new window. * If `window-id` is omitted, then create a new window. ## References * Spec: #8135 * Megathread: #5000 * Project: projects/5 ## PR Checklist * [x] Closes #4472 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - **sure does** ## Detailed Description of the Pull Request / Additional comments Note that `wt -w 1 -d c:\foo cmd.exe` does work, by causing window 1 to change There are limitations, and there are plenty of things to work on in the future: * [ ] We don't support names for windows yet * [ ] We don't support window glomming by default, or a setting to configure what happens when `-w` is omitted. I thought it best to lay the groundwork first, then come back to that. * [ ] `-w 0` currently just uses the "last activated" window, not "the current". There's more follow-up work to try and smartly find the actual window we're being called from. * [ ] Basically anything else that's listed in projects/5. I'm cutting this PR where it currently is, because this is already a huge PR. I believe the remaining tasks will all be easier to land, once this is in. ## Validation Steps Performed I've been creating windows, and closing them, and running cmdlines for a while now. I'm gonna keep doing that while the PR is open, till no bugs remain. # TODOs * [x] There are a bunch of `GetID`, `GetPID` calls that aren't try/caught 😬 - [x] `Monarch.cpp` - [x] `Peasant.cpp` - [x] `WindowManager.cpp` - [x] `AppHost.cpp` * [x] If the monarch gets hung, then _you can't launch any Terminals_ 😨 We should handle this gracefully. - Proposed idea: give the Monarch some time to respond to a proposal for a commandline. If there's no response in that timeframe, this window is now a _hermit_, outside of society entirely. It can't be elected Monarch. It can't receive command lines. It has no ID. - Could we gracefully recover from such a state? maybe, probably not though. - Same deal if a peasant hangs, it could end up hanging the monarch, right? Like if you do `wt -w 2`, and `2` is hung, then does the monarch get hung waiting on the hung peasant? - After talking with @miniksa, **we're gonna punt this from the initial implementation**. If people legit hit this in the wild, we'll fix it then.
2021-02-10 12:28:09 +01:00
static void _killPeasant(const com_ptr<Remoting::implementation::Monarch>& m,
const uint64_t peasantID);
static void _findTargetWindowHelper(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args);
Add support for naming windows with the `-w` parameter (#9300) This finishes the implementation of `--window` to also accept a string as the "name" of the window. So you can say ```sh wt -w foo new-tab wt -w foo split-pane ``` and have both those commands execute in the same window, the one named "foo". This is just slightly more ergonomic than manually using the IDs of windows. In the future, I'll be working on renaming windows, and displaying these names. > #### `--window,-w <window-id>` > Run these commands in the given Windows Terminal session. This enables opening > new tabs, splits, etc. in already running Windows Terminal windows. > * If `window-id` is `0`, run the given commands in _the current window_. > * If `window-id` is a negative number, or the reserved name `new`, run the > commands in a _new_ Terminal window. > * If `window-id` is the ID or name of an existing window, then run the > commandline in that window. > * If `window-id` is _not_ the ID or name of an existing window, create a new > window. That window will be assigned the ID or name provided in the > commandline. The provided subcommands will be run in that new window. > * If `window-id` is omitted, then obey the value of `windowingBehavior` when > determining which window to run the command in. Before this PR, I think we didn't actually properly support assigning the id with `wt -w 12345`. If `12345` didn't exist, it would make a new window, but just assign it the next id, not assign it 12345. ## References * #4472, #8135 * https://github.com/microsoft/terminal/projects/5 ## Validation Steps Performed Ran tests Messed with naming windows, working as expected. Closes https://github.com/microsoft/terminal/projects/5#card-51431478
2021-03-17 20:28:01 +01:00
static void _findTargetWindowByNameHelper(const winrt::Windows::Foundation::IInspectable& sender,
const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args);
Add `Microsoft.Terminal.Remoting.dll` (#8607) Adds a `Microsoft.Terminal.Remoting.dll` to our solution. This DLL will be responsible for all the Monarch/Peasant work that's been described in #7240 & #8135. This PR does _not_ implement the Monarch/Peasant architecture in any significant way. The goal of this PR is to just to establish the project layout, and the most basic connections. This should make reviewing the actual meat of the implementation (in a later PR) easier. It will also give us the opportunity to include some of the basic weird things we're doing (with `CoRegisterClass`) in the Terminal _now_, and get them selfhosted, before building on them too much. This PR does have windows registering the `Monarch` class with COM. When windows are created, they'll as the Monarch if they should create a new window or not. In this PR, the Monarch will always reply "yes, please make a new window". Similar to other projects in our solution, we're adding 3 projects here: * `Microsoft.Terminal.Remoting.lib`: the actual implementation, as a static lib. * `Microsoft.Terminal.Remoting.dll`: The implementation linked as a DLL, for use in `WindowsTerminal.exe`. * `Remoting.UnitTests.dll`: A unit test dll that links with the static lib. There are plenty of TODOs scattered about the code. Clearly, most of this isn't implemented yet, but I do have more WIP branches. I'm using [`projects/5`](https://github.com/microsoft/terminal/projects/5) as my notation for TODOs that are too small for an issue, but are part of the whole Process Model 2.0 work. ## References * #5000 - this is the process model megathread * #7240 - The process model 2.0 spec. * #8135 - the window management spec. (please review me, I have 0/3 signoffs even after the discussion we had 😢) * #8171 - the Monarch/peasant sample. (please review me, I have 1/2) ## PR Checklist * [x] Closes nothing, this is just infrastructure * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated
2021-01-07 23:59:37 +01:00
};
Add support for running a commandline in another WT window (#8898) ## Summary of the Pull Request **If you're reading this PR and haven't signed off on #8135, go there first.** ![window-management-000](https://user-images.githubusercontent.com/18356694/103932910-25199380-50e8-11eb-97e3-594a31da62d2.gif) This provides the basic parts of the implementation of #4472. Namely: * We add support for the `--window,-w <window-id>` argument to `wt.exe`, to allow a commandline to be given to another window. * If `window-id` is `0`, run the given commands in _the current window_. * If `window-id` is a negative number, run the commands in a _new_ Terminal window. * If `window-id` is the ID of an existing window, then run the commandline in that window. * If `window-id` is _not_ the ID of an existing window, create a new window. That window will be assigned the ID provided in the commandline. The provided subcommands will be run in that new window. * If `window-id` is omitted, then create a new window. ## References * Spec: #8135 * Megathread: #5000 * Project: projects/5 ## PR Checklist * [x] Closes #4472 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - **sure does** ## Detailed Description of the Pull Request / Additional comments Note that `wt -w 1 -d c:\foo cmd.exe` does work, by causing window 1 to change There are limitations, and there are plenty of things to work on in the future: * [ ] We don't support names for windows yet * [ ] We don't support window glomming by default, or a setting to configure what happens when `-w` is omitted. I thought it best to lay the groundwork first, then come back to that. * [ ] `-w 0` currently just uses the "last activated" window, not "the current". There's more follow-up work to try and smartly find the actual window we're being called from. * [ ] Basically anything else that's listed in projects/5. I'm cutting this PR where it currently is, because this is already a huge PR. I believe the remaining tasks will all be easier to land, once this is in. ## Validation Steps Performed I've been creating windows, and closing them, and running cmdlines for a while now. I'm gonna keep doing that while the PR is open, till no bugs remain. # TODOs * [x] There are a bunch of `GetID`, `GetPID` calls that aren't try/caught 😬 - [x] `Monarch.cpp` - [x] `Peasant.cpp` - [x] `WindowManager.cpp` - [x] `AppHost.cpp` * [x] If the monarch gets hung, then _you can't launch any Terminals_ 😨 We should handle this gracefully. - Proposed idea: give the Monarch some time to respond to a proposal for a commandline. If there's no response in that timeframe, this window is now a _hermit_, outside of society entirely. It can't be elected Monarch. It can't receive command lines. It has no ID. - Could we gracefully recover from such a state? maybe, probably not though. - Same deal if a peasant hangs, it could end up hanging the monarch, right? Like if you do `wt -w 2`, and `2` is hung, then does the monarch get hung waiting on the hung peasant? - After talking with @miniksa, **we're gonna punt this from the initial implementation**. If people legit hit this in the wild, we'll fix it then.
2021-02-10 12:28:09 +01:00
// Helper to replace the specified peasant in a monarch with a
// "DeadPeasant", which will emulate what happens when the peasant process
// dies.
void RemotingTests::_killPeasant(const com_ptr<Remoting::implementation::Monarch>& m,
const uint64_t peasantID)
{
if (peasantID <= 0)
{
return;
}
com_ptr<DeadPeasant> tombstone;
tombstone.attach(new DeadPeasant());
m->_peasants[peasantID] = *tombstone;
}
// Helper to get the first argument out of the commandline, and try to
// convert it to an int.
void RemotingTests::_findTargetWindowHelper(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args)
{
const auto arguments = args.Args().Commandline();
if (arguments.size() > 0)
{
const auto index = std::stoi(arguments.at(0).c_str());
args.ResultTargetWindow(index >= 0 ? index : -1);
Add support for running a commandline in another WT window (#8898) ## Summary of the Pull Request **If you're reading this PR and haven't signed off on #8135, go there first.** ![window-management-000](https://user-images.githubusercontent.com/18356694/103932910-25199380-50e8-11eb-97e3-594a31da62d2.gif) This provides the basic parts of the implementation of #4472. Namely: * We add support for the `--window,-w <window-id>` argument to `wt.exe`, to allow a commandline to be given to another window. * If `window-id` is `0`, run the given commands in _the current window_. * If `window-id` is a negative number, run the commands in a _new_ Terminal window. * If `window-id` is the ID of an existing window, then run the commandline in that window. * If `window-id` is _not_ the ID of an existing window, create a new window. That window will be assigned the ID provided in the commandline. The provided subcommands will be run in that new window. * If `window-id` is omitted, then create a new window. ## References * Spec: #8135 * Megathread: #5000 * Project: projects/5 ## PR Checklist * [x] Closes #4472 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - **sure does** ## Detailed Description of the Pull Request / Additional comments Note that `wt -w 1 -d c:\foo cmd.exe` does work, by causing window 1 to change There are limitations, and there are plenty of things to work on in the future: * [ ] We don't support names for windows yet * [ ] We don't support window glomming by default, or a setting to configure what happens when `-w` is omitted. I thought it best to lay the groundwork first, then come back to that. * [ ] `-w 0` currently just uses the "last activated" window, not "the current". There's more follow-up work to try and smartly find the actual window we're being called from. * [ ] Basically anything else that's listed in projects/5. I'm cutting this PR where it currently is, because this is already a huge PR. I believe the remaining tasks will all be easier to land, once this is in. ## Validation Steps Performed I've been creating windows, and closing them, and running cmdlines for a while now. I'm gonna keep doing that while the PR is open, till no bugs remain. # TODOs * [x] There are a bunch of `GetID`, `GetPID` calls that aren't try/caught 😬 - [x] `Monarch.cpp` - [x] `Peasant.cpp` - [x] `WindowManager.cpp` - [x] `AppHost.cpp` * [x] If the monarch gets hung, then _you can't launch any Terminals_ 😨 We should handle this gracefully. - Proposed idea: give the Monarch some time to respond to a proposal for a commandline. If there's no response in that timeframe, this window is now a _hermit_, outside of society entirely. It can't be elected Monarch. It can't receive command lines. It has no ID. - Could we gracefully recover from such a state? maybe, probably not though. - Same deal if a peasant hangs, it could end up hanging the monarch, right? Like if you do `wt -w 2`, and `2` is hung, then does the monarch get hung waiting on the hung peasant? - After talking with @miniksa, **we're gonna punt this from the initial implementation**. If people legit hit this in the wild, we'll fix it then.
2021-02-10 12:28:09 +01:00
}
}
Add support for naming windows with the `-w` parameter (#9300) This finishes the implementation of `--window` to also accept a string as the "name" of the window. So you can say ```sh wt -w foo new-tab wt -w foo split-pane ``` and have both those commands execute in the same window, the one named "foo". This is just slightly more ergonomic than manually using the IDs of windows. In the future, I'll be working on renaming windows, and displaying these names. > #### `--window,-w <window-id>` > Run these commands in the given Windows Terminal session. This enables opening > new tabs, splits, etc. in already running Windows Terminal windows. > * If `window-id` is `0`, run the given commands in _the current window_. > * If `window-id` is a negative number, or the reserved name `new`, run the > commands in a _new_ Terminal window. > * If `window-id` is the ID or name of an existing window, then run the > commandline in that window. > * If `window-id` is _not_ the ID or name of an existing window, create a new > window. That window will be assigned the ID or name provided in the > commandline. The provided subcommands will be run in that new window. > * If `window-id` is omitted, then obey the value of `windowingBehavior` when > determining which window to run the command in. Before this PR, I think we didn't actually properly support assigning the id with `wt -w 12345`. If `12345` didn't exist, it would make a new window, but just assign it the next id, not assign it 12345. ## References * #4472, #8135 * https://github.com/microsoft/terminal/projects/5 ## Validation Steps Performed Ran tests Messed with naming windows, working as expected. Closes https://github.com/microsoft/terminal/projects/5#card-51431478
2021-03-17 20:28:01 +01:00
// Helper to get the first argument out of the commandline, and return it as
// a name to use.
void RemotingTests::_findTargetWindowByNameHelper(const winrt::Windows::Foundation::IInspectable& /*sender*/,
const winrt::Microsoft::Terminal::Remoting::FindTargetWindowArgs& args)
{
const auto arguments = args.Args().Commandline();
if (arguments.size() > 0)
{
args.ResultTargetWindow(WindowingBehaviorUseName);
args.ResultTargetWindowName(arguments.at(0));
}
}
Add `Microsoft.Terminal.Remoting.dll` (#8607) Adds a `Microsoft.Terminal.Remoting.dll` to our solution. This DLL will be responsible for all the Monarch/Peasant work that's been described in #7240 & #8135. This PR does _not_ implement the Monarch/Peasant architecture in any significant way. The goal of this PR is to just to establish the project layout, and the most basic connections. This should make reviewing the actual meat of the implementation (in a later PR) easier. It will also give us the opportunity to include some of the basic weird things we're doing (with `CoRegisterClass`) in the Terminal _now_, and get them selfhosted, before building on them too much. This PR does have windows registering the `Monarch` class with COM. When windows are created, they'll as the Monarch if they should create a new window or not. In this PR, the Monarch will always reply "yes, please make a new window". Similar to other projects in our solution, we're adding 3 projects here: * `Microsoft.Terminal.Remoting.lib`: the actual implementation, as a static lib. * `Microsoft.Terminal.Remoting.dll`: The implementation linked as a DLL, for use in `WindowsTerminal.exe`. * `Remoting.UnitTests.dll`: A unit test dll that links with the static lib. There are plenty of TODOs scattered about the code. Clearly, most of this isn't implemented yet, but I do have more WIP branches. I'm using [`projects/5`](https://github.com/microsoft/terminal/projects/5) as my notation for TODOs that are too small for an issue, but are part of the whole Process Model 2.0 work. ## References * #5000 - this is the process model megathread * #7240 - The process model 2.0 spec. * #8135 - the window management spec. (please review me, I have 0/3 signoffs even after the discussion we had 😢) * #8171 - the Monarch/peasant sample. (please review me, I have 1/2) ## PR Checklist * [x] Closes nothing, this is just infrastructure * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated
2021-01-07 23:59:37 +01:00
void RemotingTests::CreateMonarch()
{
auto m1 = winrt::make_self<Remoting::implementation::Monarch>();
VERIFY_IS_NOT_NULL(m1);
VERIFY_ARE_EQUAL(GetCurrentProcessId(),
m1->GetPID(),
L"A Monarch without an explicit PID should use the current PID");
Log::Comment(L"That's what we need for window process management, but for tests, it'll be more useful to fake the PIDs.");
auto expectedFakePID = 1234u;
MAKE_MONARCH(m2, expectedFakePID);
VERIFY_IS_NOT_NULL(m2);
VERIFY_ARE_EQUAL(expectedFakePID,
m2->GetPID(),
L"A Monarch with an explicit PID should use the one we provided");
}
void RemotingTests::CreatePeasant()
{
auto p1 = winrt::make_self<Remoting::implementation::Peasant>();
VERIFY_IS_NOT_NULL(p1);
VERIFY_ARE_EQUAL(GetCurrentProcessId(),
p1->GetPID(),
L"A Peasant without an explicit PID should use the current PID");
Log::Comment(L"That's what we need for window process management, but for tests, it'll be more useful to fake the PIDs.");
auto expectedFakePID = 2345u;
MAKE_PEASANT(p2, expectedFakePID);
VERIFY_IS_NOT_NULL(p2);
VERIFY_ARE_EQUAL(expectedFakePID,
p2->GetPID(),
L"A Peasant with an explicit PID should use the one we provided");
}
Add support for running a commandline in another WT window (#8898) ## Summary of the Pull Request **If you're reading this PR and haven't signed off on #8135, go there first.** ![window-management-000](https://user-images.githubusercontent.com/18356694/103932910-25199380-50e8-11eb-97e3-594a31da62d2.gif) This provides the basic parts of the implementation of #4472. Namely: * We add support for the `--window,-w <window-id>` argument to `wt.exe`, to allow a commandline to be given to another window. * If `window-id` is `0`, run the given commands in _the current window_. * If `window-id` is a negative number, run the commands in a _new_ Terminal window. * If `window-id` is the ID of an existing window, then run the commandline in that window. * If `window-id` is _not_ the ID of an existing window, create a new window. That window will be assigned the ID provided in the commandline. The provided subcommands will be run in that new window. * If `window-id` is omitted, then create a new window. ## References * Spec: #8135 * Megathread: #5000 * Project: projects/5 ## PR Checklist * [x] Closes #4472 * [x] I work here * [x] Tests added/passed * [ ] Requires documentation to be updated - **sure does** ## Detailed Description of the Pull Request / Additional comments Note that `wt -w 1 -d c:\foo cmd.exe` does work, by causing window 1 to change There are limitations, and there are plenty of things to work on in the future: * [ ] We don't support names for windows yet * [ ] We don't support window glomming by default, or a setting to configure what happens when `-w` is omitted. I thought it best to lay the groundwork first, then come back to that. * [ ] `-w 0` currently just uses the "last activated" window, not "the current". There's more follow-up work to try and smartly find the actual window we're being called from. * [ ] Basically anything else that's listed in projects/5. I'm cutting this PR where it currently is, because this is already a huge PR. I believe the remaining tasks will all be easier to land, once this is in. ## Validation Steps Performed I've been creating windows, and closing them, and running cmdlines for a while now. I'm gonna keep doing that while the PR is open, till no bugs remain. # TODOs * [x] There are a bunch of `GetID`, `GetPID` calls that aren't try/caught 😬 - [x] `Monarch.cpp` - [x] `Peasant.cpp` - [x] `WindowManager.cpp` - [x] `AppHost.cpp` * [x] If the monarch gets hung, then _you can't launch any Terminals_ 😨 We should handle this gracefully. - Proposed idea: give the Monarch some time to respond to a proposal for a commandline. If there's no response in that timeframe, this window is now a _hermit_, outside of society entirely. It can't be elected Monarch. It can't receive command lines. It has no ID. - Could we gracefully recover from such a state? maybe, probably not though. - Same deal if a peasant hangs, it could end up hanging the monarch, right? Like if you do `wt -w 2`, and `2` is hung, then does the monarch get hung waiting on the hung peasant? - After talking with @miniksa, **we're gonna punt this from the initial implementation**. If people legit hit this in the wild, we'll fix it then.
2021-02-10 12:28:09 +01:00
void RemotingTests::CreatePeasantWithNew()
{
Log::Comment(L"The same thing as the above test, but with `new` instead of insanity on the stack");
auto p1 = winrt::make_self<Remoting::implementation::Peasant>();
VERIFY_IS_NOT_NULL(p1);
VERIFY_ARE_EQUAL(GetCurrentProcessId(),
p1->GetPID(),
L"A Peasant without an explicit PID should use the current PID");
auto expectedFakePID = 2345u;
com_ptr<Remoting::implementation::Peasant> p2;
VERIFY_IS_NULL(p2);
p2.attach(new Remoting::implementation::Peasant(expectedFakePID));
VERIFY_IS_NOT_NULL(p2);
VERIFY_ARE_EQUAL(expectedFakePID,
p2->GetPID(),
L"A Peasant with an explicit PID should use the one we provided");
}
void RemotingTests::AddPeasants()
{
const auto monarch0PID = 12345u;
const auto peasant1PID = 23456u;
const auto peasant2PID = 34567u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
com_ptr<Remoting::implementation::Peasant> p2;
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
VERIFY_IS_NOT_NULL(m0);
VERIFY_IS_NOT_NULL(p1);
VERIFY_IS_NOT_NULL(p2);
VERIFY_ARE_EQUAL(0, p1->GetID());
VERIFY_ARE_EQUAL(0, p2->GetID());
m0->AddPeasant(*p1);
m0->AddPeasant(*p2);
VERIFY_ARE_EQUAL(1, p1->GetID());
VERIFY_ARE_EQUAL(2, p2->GetID());
}
void RemotingTests::GetPeasantsByID()
{
const auto monarch0PID = 12345u;
const auto peasant1PID = 23456u;
const auto peasant2PID = 34567u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
com_ptr<Remoting::implementation::Peasant> p2;
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
VERIFY_IS_NOT_NULL(m0);
VERIFY_IS_NOT_NULL(p1);
VERIFY_IS_NOT_NULL(p2);
VERIFY_ARE_EQUAL(0, p1->GetID());
VERIFY_ARE_EQUAL(0, p2->GetID());
m0->AddPeasant(*p1);
m0->AddPeasant(*p2);
VERIFY_ARE_EQUAL(1, p1->GetID());
VERIFY_ARE_EQUAL(2, p2->GetID());
auto maybeP1 = m0->_getPeasant(1);
VERIFY_IS_NOT_NULL(maybeP1);
VERIFY_ARE_EQUAL(peasant1PID, maybeP1.GetPID());
auto maybeP2 = m0->_getPeasant(2);
VERIFY_IS_NOT_NULL(maybeP2);
VERIFY_ARE_EQUAL(peasant2PID, maybeP2.GetPID());
}
void RemotingTests::AddPeasantsToNewMonarch()
{
const auto monarch0PID = 12345u;
const auto peasant1PID = 23456u;
const auto peasant2PID = 34567u;
const auto monarch3PID = 45678u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
com_ptr<Remoting::implementation::Peasant> p2;
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
com_ptr<Remoting::implementation::Monarch> m3;
m3.attach(new Remoting::implementation::Monarch(monarch3PID));
VERIFY_IS_NOT_NULL(m0);
VERIFY_IS_NOT_NULL(p1);
VERIFY_IS_NOT_NULL(p2);
VERIFY_IS_NOT_NULL(m3);
VERIFY_ARE_EQUAL(0, p1->GetID());
VERIFY_ARE_EQUAL(0, p2->GetID());
m0->AddPeasant(*p1);
m0->AddPeasant(*p2);
VERIFY_ARE_EQUAL(1, p1->GetID());
VERIFY_ARE_EQUAL(2, p2->GetID());
m3->AddPeasant(*p1);
m3->AddPeasant(*p2);
VERIFY_ARE_EQUAL(1, p1->GetID());
VERIFY_ARE_EQUAL(2, p2->GetID());
}
void RemotingTests::RemovePeasantFromMonarchWhenFreed()
{
const auto monarch0PID = 12345u;
const auto peasant1PID = 23456u;
const auto peasant2PID = 34567u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
com_ptr<Remoting::implementation::Peasant> p2;
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
VERIFY_IS_NOT_NULL(m0);
VERIFY_IS_NOT_NULL(p1);
VERIFY_IS_NOT_NULL(p2);
VERIFY_ARE_EQUAL(0, p1->GetID());
VERIFY_ARE_EQUAL(0, p2->GetID());
m0->AddPeasant(*p1);
m0->AddPeasant(*p2);
VERIFY_ARE_EQUAL(1, p1->GetID());
VERIFY_ARE_EQUAL(2, p2->GetID());
VERIFY_ARE_EQUAL(2u, m0->_peasants.size());
Log::Comment(L"Kill peasant 1. Make sure that it gets removed from the monarch.");
RemotingTests::_killPeasant(m0, p1->GetID());
auto maybeP2 = m0->_getPeasant(2);
VERIFY_IS_NOT_NULL(maybeP2);
VERIFY_ARE_EQUAL(peasant2PID, maybeP2.GetPID());
auto maybeP1 = m0->_getPeasant(1);
VERIFY_IS_NULL(maybeP1);
VERIFY_ARE_EQUAL(1u, m0->_peasants.size());
}
void RemotingTests::ProposeCommandlineNoWindow()
{
Log::Comment(L"Test proposing a commandline that doesn't have a window specified in it");
const auto monarch0PID = 12345u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
VERIFY_IS_NOT_NULL(m0);
m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);
std::vector<winrt::hstring> args{};
Remoting::CommandlineArgs eventArgs{ { args }, { L"" } };
auto result = m0->ProposeCommandline(eventArgs);
VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow());
VERIFY_ARE_EQUAL(false, (bool)result.Id());
Log::Comment(L"Add a peasant");
const auto peasant1PID = 23456u;
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
VERIFY_IS_NOT_NULL(p1);
m0->AddPeasant(*p1);
Log::Comment(L"Propose the same args again after adding a peasant - we should still return {create new window, no ID}");
result = m0->ProposeCommandline(eventArgs);
VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow());
VERIFY_ARE_EQUAL(false, (bool)result.Id());
}
void RemotingTests::ProposeCommandlineGivenWindow()
{
Log::Comment(L"Test proposing a commandline for a window that currently exists");
const auto monarch0PID = 12345u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
VERIFY_IS_NOT_NULL(m0);
m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);
Log::Comment(L"Add a peasant");
const auto peasant1PID = 23456u;
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
VERIFY_IS_NOT_NULL(p1);
m0->AddPeasant(*p1);
p1->ExecuteCommandlineRequested([&](auto&&, const Remoting::CommandlineArgs& cmdlineArgs) {
Log::Comment(L"Commandline dispatched to p1");
VERIFY_IS_GREATER_THAN(cmdlineArgs.Commandline().size(), 1u);
VERIFY_ARE_EQUAL(L"arg[1]", cmdlineArgs.Commandline().at(1));
});
std::vector<winrt::hstring> args{ L"1", L"arg[1]" };
Remoting::CommandlineArgs eventArgs{ { args }, { L"" } };
auto result = m0->ProposeCommandline(eventArgs);
VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow());
VERIFY_ARE_EQUAL(false, (bool)result.Id());
}
void RemotingTests::ProposeCommandlineNegativeWindow()
{
Log::Comment(L"Test proposing a commandline for an invalid window ID, like -1");
const auto monarch0PID = 12345u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
VERIFY_IS_NOT_NULL(m0);
m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);
Log::Comment(L"Add a peasant");
const auto peasant1PID = 23456u;
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
VERIFY_IS_NOT_NULL(p1);
m0->AddPeasant(*p1);
{
std::vector<winrt::hstring> args{ L"-1" };
Remoting::CommandlineArgs eventArgs{ { args }, { L"" } };
auto result = m0->ProposeCommandline(eventArgs);
VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow());
VERIFY_ARE_EQUAL(false, (bool)result.Id());
}
{
std::vector<winrt::hstring> args{ L"-2" };
Remoting::CommandlineArgs eventArgs{ { args }, { L"" } };
auto result = m0->ProposeCommandline(eventArgs);
VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow());
VERIFY_ARE_EQUAL(false, (bool)result.Id());
}
}
void RemotingTests::ProposeCommandlineCurrentWindow()
{
Log::Comment(L"Test proposing a commandline for the current window (ID=0)");
const auto monarch0PID = 12345u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
VERIFY_IS_NOT_NULL(m0);
m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);
Log::Comment(L"Add a peasant");
const auto peasant1PID = 23456u;
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
VERIFY_IS_NOT_NULL(p1);
m0->AddPeasant(*p1);
p1->ExecuteCommandlineRequested([&](auto&&, const Remoting::CommandlineArgs& cmdlineArgs) {
Log::Comment(L"Commandline dispatched to p1");
VERIFY_IS_GREATER_THAN(cmdlineArgs.Commandline().size(), 1u);
VERIFY_ARE_EQUAL(L"arg[1]", cmdlineArgs.Commandline().at(1));
});
std::vector<winrt::hstring> p1Args{ L"0", L"arg[1]" };
std::vector<winrt::hstring> p2Args{ L"0", L"this is for p2" };
{
Log::Comment(L"Manually activate the first peasant");
// This would usually happen immediately when the window is created, but
// there's no actual window in these tests.
Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
winrt::guid{},
winrt::clock().now() };
p1->ActivateWindow(activatedArgs);
Remoting::CommandlineArgs eventArgs{ { p1Args }, { L"" } };
auto result = m0->ProposeCommandline(eventArgs);
VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow());
VERIFY_ARE_EQUAL(false, (bool)result.Id());
}
Log::Comment(L"Add a second peasant");
const auto peasant2PID = 34567u;
com_ptr<Remoting::implementation::Peasant> p2;
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
VERIFY_IS_NOT_NULL(p2);
m0->AddPeasant(*p2);
p2->ExecuteCommandlineRequested([&](auto&&, const Remoting::CommandlineArgs& cmdlineArgs) {
Log::Comment(L"Commandline dispatched to p2");
VERIFY_IS_GREATER_THAN(cmdlineArgs.Commandline().size(), 1u);
VERIFY_ARE_EQUAL(L"this is for p2", cmdlineArgs.Commandline().at(1));
});
{
Log::Comment(L"Activate the second peasant");
Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
winrt::guid{},
winrt::clock().now() };
p2->ActivateWindow(activatedArgs);
Log::Comment(L"Send a commandline to the current window, which should be p2");
Remoting::CommandlineArgs eventArgs{ { p2Args }, { L"" } };
auto result = m0->ProposeCommandline(eventArgs);
VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow());
VERIFY_ARE_EQUAL(false, (bool)result.Id());
}
{
Log::Comment(L"Reactivate the first peasant");
Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
winrt::guid{},
winrt::clock().now() };
p1->ActivateWindow(activatedArgs);
Log::Comment(L"Send a commandline to the current window, which should be p1 again");
Remoting::CommandlineArgs eventArgs{ { p1Args }, { L"" } };
auto result = m0->ProposeCommandline(eventArgs);
VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow());
VERIFY_ARE_EQUAL(false, (bool)result.Id());
}
}
void RemotingTests::ProposeCommandlineNonExistentWindow()
{
Log::Comment(L"Test proposing a commandline for an ID that doesn't have a current peasant");
const auto monarch0PID = 12345u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
VERIFY_IS_NOT_NULL(m0);
m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);
Log::Comment(L"Add a peasant");
const auto peasant1PID = 23456u;
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
VERIFY_IS_NOT_NULL(p1);
m0->AddPeasant(*p1);
{
std::vector<winrt::hstring> args{ L"2" };
Remoting::CommandlineArgs eventArgs{ { args }, { L"" } };
auto result = m0->ProposeCommandline(eventArgs);
VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow());
VERIFY_ARE_EQUAL(true, (bool)result.Id());
VERIFY_ARE_EQUAL(2u, result.Id().Value());
}
{
std::vector<winrt::hstring> args{ L"10" };
Remoting::CommandlineArgs eventArgs{ { args }, { L"" } };
auto result = m0->ProposeCommandline(eventArgs);
VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow());
VERIFY_ARE_EQUAL(true, (bool)result.Id());
VERIFY_ARE_EQUAL(10u, result.Id().Value());
}
}
void RemotingTests::ProposeCommandlineDeadWindow()
{
Log::Comment(L"Test proposing a commandline for a peasant that previously died");
const auto monarch0PID = 12345u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
VERIFY_IS_NOT_NULL(m0);
m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);
Log::Comment(L"Add a peasant");
const auto peasant1PID = 23456u;
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
VERIFY_IS_NOT_NULL(p1);
m0->AddPeasant(*p1);
p1->ExecuteCommandlineRequested([&](auto&&, const Remoting::CommandlineArgs& /*cmdlineArgs*/) {
Log::Comment(L"Commandline dispatched to p1");
VERIFY_IS_TRUE(false, L"This should not happen, this peasant should be dead.");
});
Log::Comment(L"Add a second peasant");
const auto peasant2PID = 34567u;
com_ptr<Remoting::implementation::Peasant> p2;
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
VERIFY_IS_NOT_NULL(p2);
m0->AddPeasant(*p2);
p2->ExecuteCommandlineRequested([&](auto&&, const Remoting::CommandlineArgs& cmdlineArgs) {
Log::Comment(L"Commandline dispatched to p2");
VERIFY_IS_GREATER_THAN(cmdlineArgs.Commandline().size(), 1u);
VERIFY_ARE_EQUAL(L"this is for p2", cmdlineArgs.Commandline().at(1));
});
std::vector<winrt::hstring> p1Args{ L"1", L"arg[1]" };
std::vector<winrt::hstring> p2Args{ L"2", L"this is for p2" };
Log::Comment(L"Kill peasant 1");
_killPeasant(m0, 1);
{
Log::Comment(L"Send a commandline to p2, who is still alive. We won't create a new window.");
Remoting::CommandlineArgs eventArgs{ { p2Args }, { L"" } };
auto result = m0->ProposeCommandline(eventArgs);
VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow());
VERIFY_ARE_EQUAL(false, (bool)result.Id());
}
{
Log::Comment(L"Send a commandline to p1, who is dead. We will create a new window.");
Remoting::CommandlineArgs eventArgs{ { p1Args }, { L"" } };
auto result = m0->ProposeCommandline(eventArgs);
VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow());
VERIFY_ARE_EQUAL(true, (bool)result.Id());
VERIFY_ARE_EQUAL(1u, result.Id().Value());
}
}
// TODO:projects/5
//
// In order to test WindowingBehaviorUseExisting, we'll have to
// create our own IVirtualDesktopManager implementation that can be subbed
// in for testing. We can't _actually_ create HWNDs as a part of the test
// and move them to different desktops. Instead, we'll have to create a stub
// impl that can fake a result for IsWindowOnCurrentVirtualDesktop.
void RemotingTests::MostRecentWindowSameDesktops()
{
Log::Comment(L"Make windows on the same desktop. Validate the contents of _mruPeasants are as expected.");
const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };
const auto monarch0PID = 12345u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
VERIFY_IS_NOT_NULL(m0);
m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);
Log::Comment(L"Add a peasant");
const auto peasant1PID = 23456u;
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
VERIFY_IS_NOT_NULL(p1);
m0->AddPeasant(*p1);
Log::Comment(L"Add a second peasant");
const auto peasant2PID = 34567u;
com_ptr<Remoting::implementation::Peasant> p2;
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
VERIFY_IS_NOT_NULL(p2);
m0->AddPeasant(*p2);
{
Log::Comment(L"Activate the first peasant, first desktop");
Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
guid1,
winrt::clock().now() };
p1->ActivateWindow(activatedArgs);
}
{
Log::Comment(L"Activate the second peasant, first desktop");
Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
guid1,
winrt::clock().now() };
p2->ActivateWindow(activatedArgs);
}
VERIFY_ARE_EQUAL(2u, m0->_mruPeasants.size());
VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[0].PeasantID());
VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[1].PeasantID());
{
Log::Comment(L"Activate the first peasant, first desktop");
Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
guid1,
winrt::clock().now() };
p1->ActivateWindow(activatedArgs);
}
VERIFY_ARE_EQUAL(2u, m0->_mruPeasants.size());
VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[0].PeasantID());
VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[1].PeasantID());
}
void RemotingTests::MostRecentWindowDifferentDesktops()
{
Log::Comment(L"Make windows on different desktops. Validate the contents of _mruPeasants are as expected.");
const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };
const auto monarch0PID = 12345u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
VERIFY_IS_NOT_NULL(m0);
m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);
Log::Comment(L"Add a peasant");
const auto peasant1PID = 23456u;
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
VERIFY_IS_NOT_NULL(p1);
m0->AddPeasant(*p1);
Log::Comment(L"Add a second peasant");
const auto peasant2PID = 34567u;
com_ptr<Remoting::implementation::Peasant> p2;
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
VERIFY_IS_NOT_NULL(p2);
m0->AddPeasant(*p2);
{
Log::Comment(L"Activate the first peasant, first desktop");
Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
guid1,
winrt::clock().now() };
p1->ActivateWindow(activatedArgs);
}
{
Log::Comment(L"Activate the second peasant, second desktop");
Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
guid2,
winrt::clock().now() };
p2->ActivateWindow(activatedArgs);
}
VERIFY_ARE_EQUAL(2u, m0->_mruPeasants.size());
VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[0].PeasantID());
VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[1].PeasantID());
Log::Comment(L"Add a third peasant");
const auto peasant3PID = 45678u;
com_ptr<Remoting::implementation::Peasant> p3;
p3.attach(new Remoting::implementation::Peasant(peasant3PID));
VERIFY_IS_NOT_NULL(p3);
m0->AddPeasant(*p3);
{
Log::Comment(L"Activate the third peasant, first desktop");
Remoting::WindowActivatedArgs activatedArgs{ p3->GetID(),
guid1,
winrt::clock().now() };
p3->ActivateWindow(activatedArgs);
}
VERIFY_ARE_EQUAL(3u, m0->_mruPeasants.size());
VERIFY_ARE_EQUAL(p3->GetID(), m0->_mruPeasants[0].PeasantID());
VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[1].PeasantID());
VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[2].PeasantID());
{
Log::Comment(L"Activate the first peasant, first desktop");
Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
guid1,
winrt::clock().now() };
p1->ActivateWindow(activatedArgs);
}
VERIFY_ARE_EQUAL(3u, m0->_mruPeasants.size());
VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[0].PeasantID());
VERIFY_ARE_EQUAL(p3->GetID(), m0->_mruPeasants[1].PeasantID());
VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[2].PeasantID());
}
void RemotingTests::MostRecentWindowMoveDesktops()
{
Log::Comment(L"Make windows on different desktops. Move one to another "
L"desktop. Validate the contents of _mruPeasants are as expected.");
const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };
const auto monarch0PID = 12345u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
VERIFY_IS_NOT_NULL(m0);
m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);
Log::Comment(L"Add a peasant");
const auto peasant1PID = 23456u;
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
VERIFY_IS_NOT_NULL(p1);
m0->AddPeasant(*p1);
Log::Comment(L"Add a second peasant");
const auto peasant2PID = 34567u;
com_ptr<Remoting::implementation::Peasant> p2;
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
VERIFY_IS_NOT_NULL(p2);
m0->AddPeasant(*p2);
{
Log::Comment(L"Activate the first peasant, first desktop");
Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
guid1,
winrt::clock().now() };
p1->ActivateWindow(activatedArgs);
}
{
Log::Comment(L"Activate the second peasant, second desktop");
Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
guid2,
winrt::clock().now() };
p2->ActivateWindow(activatedArgs);
}
VERIFY_ARE_EQUAL(2u, m0->_mruPeasants.size());
VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[0].PeasantID());
VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[1].PeasantID());
Log::Comment(L"Add a third peasant");
const auto peasant3PID = 45678u;
com_ptr<Remoting::implementation::Peasant> p3;
p3.attach(new Remoting::implementation::Peasant(peasant3PID));
VERIFY_IS_NOT_NULL(p3);
m0->AddPeasant(*p3);
{
Log::Comment(L"Activate the third peasant, first desktop");
Remoting::WindowActivatedArgs activatedArgs{ p3->GetID(),
guid1,
winrt::clock().now() };
p3->ActivateWindow(activatedArgs);
}
VERIFY_ARE_EQUAL(3u, m0->_mruPeasants.size());
VERIFY_ARE_EQUAL(p3->GetID(), m0->_mruPeasants[0].PeasantID());
VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[1].PeasantID());
VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[2].PeasantID());
{
Log::Comment(L"Activate the first peasant, second desktop");
Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
guid2,
winrt::clock().now() };
p1->ActivateWindow(activatedArgs);
}
VERIFY_ARE_EQUAL(3u, m0->_mruPeasants.size());
VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[0].PeasantID());
VERIFY_ARE_EQUAL(p3->GetID(), m0->_mruPeasants[1].PeasantID());
VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[2].PeasantID());
{
Log::Comment(L"Activate the third peasant, second desktop");
Remoting::WindowActivatedArgs activatedArgs{ p3->GetID(),
guid2,
winrt::clock().now() };
p3->ActivateWindow(activatedArgs);
}
VERIFY_ARE_EQUAL(3u, m0->_mruPeasants.size());
VERIFY_ARE_EQUAL(p3->GetID(), m0->_mruPeasants[0].PeasantID());
VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[1].PeasantID());
VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[2].PeasantID());
{
Log::Comment(L"Activate the second peasant, first desktop");
Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
guid1,
winrt::clock().now() };
p2->ActivateWindow(activatedArgs);
}
VERIFY_ARE_EQUAL(3u, m0->_mruPeasants.size());
VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[0].PeasantID());
VERIFY_ARE_EQUAL(p3->GetID(), m0->_mruPeasants[1].PeasantID());
VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[2].PeasantID());
}
void RemotingTests::GetMostRecentAnyDesktop()
{
Log::Comment(L"Make windows on different desktops. Confirm that "
L"getting the most recent of all windows works as expected.");
const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };
const auto monarch0PID = 12345u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
VERIFY_IS_NOT_NULL(m0);
m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);
Log::Comment(L"Add a peasant");
const auto peasant1PID = 23456u;
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
VERIFY_IS_NOT_NULL(p1);
m0->AddPeasant(*p1);
Log::Comment(L"Add a second peasant");
const auto peasant2PID = 34567u;
com_ptr<Remoting::implementation::Peasant> p2;
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
VERIFY_IS_NOT_NULL(p2);
m0->AddPeasant(*p2);
{
Log::Comment(L"Activate the first peasant, first desktop");
Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
guid1,
winrt::clock().now() };
p1->ActivateWindow(activatedArgs);
}
{
Log::Comment(L"Activate the second peasant, second desktop");
Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
guid2,
winrt::clock().now() };
p2->ActivateWindow(activatedArgs);
}
VERIFY_ARE_EQUAL(p2->GetID(), m0->_getMostRecentPeasantID(false));
Log::Comment(L"Add a third peasant");
const auto peasant3PID = 45678u;
com_ptr<Remoting::implementation::Peasant> p3;
p3.attach(new Remoting::implementation::Peasant(peasant3PID));
VERIFY_IS_NOT_NULL(p3);
m0->AddPeasant(*p3);
{
Log::Comment(L"Activate the third peasant, first desktop");
Remoting::WindowActivatedArgs activatedArgs{ p3->GetID(),
guid1,
winrt::clock().now() };
p3->ActivateWindow(activatedArgs);
}
VERIFY_ARE_EQUAL(p3->GetID(), m0->_getMostRecentPeasantID(false));
{
Log::Comment(L"Activate the first peasant, second desktop");
Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
guid2,
winrt::clock().now() };
p1->ActivateWindow(activatedArgs);
}
VERIFY_ARE_EQUAL(p1->GetID(), m0->_getMostRecentPeasantID(false));
}
void RemotingTests::MostRecentIsDead()
{
Log::Comment(L"Make two windows. Activate the first, then the second. "
L"Kill the second. The most recent should be the _first_ window.");
const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
const winrt::guid guid2{ Utils::GuidFromString(L"{22222222-2222-2222-2222-222222222222}") };
const auto monarch0PID = 12345u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
VERIFY_IS_NOT_NULL(m0);
m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowHelper);
Log::Comment(L"Add a peasant");
const auto peasant1PID = 23456u;
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
VERIFY_IS_NOT_NULL(p1);
m0->AddPeasant(*p1);
Log::Comment(L"Add a second peasant");
const auto peasant2PID = 34567u;
com_ptr<Remoting::implementation::Peasant> p2;
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
VERIFY_IS_NOT_NULL(p2);
m0->AddPeasant(*p2);
{
Log::Comment(L"Activate the first peasant, first desktop");
Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
guid1,
winrt::clock().now() };
p1->ActivateWindow(activatedArgs);
}
{
Log::Comment(L"Activate the second peasant, first desktop");
Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
guid1,
winrt::clock().now() };
p2->ActivateWindow(activatedArgs);
}
VERIFY_ARE_EQUAL(2u, m0->_mruPeasants.size());
VERIFY_ARE_EQUAL(p2->GetID(), m0->_mruPeasants[0].PeasantID());
VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[1].PeasantID());
Log::Comment(L"Kill peasant 2");
RemotingTests::_killPeasant(m0, p2->GetID());
Log::Comment(L"Peasant 1 should be the new MRU peasant");
VERIFY_ARE_EQUAL(p1->GetID(), m0->_getMostRecentPeasantID(false));
Log::Comment(L"Peasant 2 should not be in the monarch at all anymore");
VERIFY_ARE_EQUAL(1u, m0->_peasants.size());
VERIFY_ARE_EQUAL(1u, m0->_mruPeasants.size());
VERIFY_ARE_EQUAL(1u, m0->_mruPeasants.size());
VERIFY_ARE_EQUAL(p1->GetID(), m0->_mruPeasants[0].PeasantID());
}
Add support for naming windows with the `-w` parameter (#9300) This finishes the implementation of `--window` to also accept a string as the "name" of the window. So you can say ```sh wt -w foo new-tab wt -w foo split-pane ``` and have both those commands execute in the same window, the one named "foo". This is just slightly more ergonomic than manually using the IDs of windows. In the future, I'll be working on renaming windows, and displaying these names. > #### `--window,-w <window-id>` > Run these commands in the given Windows Terminal session. This enables opening > new tabs, splits, etc. in already running Windows Terminal windows. > * If `window-id` is `0`, run the given commands in _the current window_. > * If `window-id` is a negative number, or the reserved name `new`, run the > commands in a _new_ Terminal window. > * If `window-id` is the ID or name of an existing window, then run the > commandline in that window. > * If `window-id` is _not_ the ID or name of an existing window, create a new > window. That window will be assigned the ID or name provided in the > commandline. The provided subcommands will be run in that new window. > * If `window-id` is omitted, then obey the value of `windowingBehavior` when > determining which window to run the command in. Before this PR, I think we didn't actually properly support assigning the id with `wt -w 12345`. If `12345` didn't exist, it would make a new window, but just assign it the next id, not assign it 12345. ## References * #4472, #8135 * https://github.com/microsoft/terminal/projects/5 ## Validation Steps Performed Ran tests Messed with naming windows, working as expected. Closes https://github.com/microsoft/terminal/projects/5#card-51431478
2021-03-17 20:28:01 +01:00
void RemotingTests::GetPeasantsByName()
{
Log::Comment(L"Test that looking up a peasant by name finds the window we expect");
const auto monarch0PID = 12345u;
const auto peasant1PID = 23456u;
const auto peasant2PID = 34567u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
com_ptr<Remoting::implementation::Peasant> p2;
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
VERIFY_IS_NOT_NULL(m0);
VERIFY_IS_NOT_NULL(p1);
VERIFY_IS_NOT_NULL(p2);
p1->WindowName(L"one");
p2->WindowName(L"two");
VERIFY_ARE_EQUAL(0, p1->GetID());
VERIFY_ARE_EQUAL(0, p2->GetID());
VERIFY_ARE_EQUAL(L"one", p1->WindowName());
VERIFY_ARE_EQUAL(L"two", p2->WindowName());
m0->AddPeasant(*p1);
m0->AddPeasant(*p2);
VERIFY_ARE_EQUAL(1, p1->GetID());
VERIFY_ARE_EQUAL(2, p2->GetID());
VERIFY_ARE_EQUAL(L"one", p1->WindowName());
VERIFY_ARE_EQUAL(L"two", p2->WindowName());
VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"one"));
VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));
Log::Comment(L"Rename p2");
p2->WindowName(L"foo");
VERIFY_ARE_EQUAL(0, m0->_lookupPeasantIdForName(L"two"));
VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"foo"));
}
void RemotingTests::AddNamedPeasantsToNewMonarch()
{
Log::Comment(L"Test that moving peasants to a new monarch persists their original names");
const auto monarch0PID = 12345u;
const auto peasant1PID = 23456u;
const auto peasant2PID = 34567u;
const auto monarch3PID = 45678u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
com_ptr<Remoting::implementation::Peasant> p2;
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
com_ptr<Remoting::implementation::Monarch> m3;
m3.attach(new Remoting::implementation::Monarch(monarch3PID));
VERIFY_IS_NOT_NULL(m0);
VERIFY_IS_NOT_NULL(p1);
VERIFY_IS_NOT_NULL(p2);
VERIFY_IS_NOT_NULL(m3);
p1->WindowName(L"one");
p2->WindowName(L"two");
VERIFY_ARE_EQUAL(0, p1->GetID());
VERIFY_ARE_EQUAL(0, p2->GetID());
m0->AddPeasant(*p1);
m0->AddPeasant(*p2);
VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"one"));
VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));
VERIFY_ARE_EQUAL(1, p1->GetID());
VERIFY_ARE_EQUAL(2, p2->GetID());
VERIFY_ARE_EQUAL(L"one", p1->WindowName());
VERIFY_ARE_EQUAL(L"two", p2->WindowName());
Log::Comment(L"When the peasants go to a new monarch, make sure they have the same name");
m3->AddPeasant(*p1);
m3->AddPeasant(*p2);
VERIFY_ARE_EQUAL(1, p1->GetID());
VERIFY_ARE_EQUAL(2, p2->GetID());
VERIFY_ARE_EQUAL(L"one", p1->WindowName());
VERIFY_ARE_EQUAL(L"two", p2->WindowName());
VERIFY_ARE_EQUAL(p1->GetID(), m3->_lookupPeasantIdForName(L"one"));
VERIFY_ARE_EQUAL(p2->GetID(), m3->_lookupPeasantIdForName(L"two"));
}
void RemotingTests::LookupNamedPeasantWhenOthersDied()
{
Log::Comment(L"Test that looking for a peasant by name when a different"
L" peasant has died cleans up the corpses of any peasants "
L"we may have tripped over.");
const auto monarch0PID = 12345u;
const auto peasant1PID = 23456u;
const auto peasant2PID = 34567u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
com_ptr<Remoting::implementation::Peasant> p2;
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
VERIFY_IS_NOT_NULL(m0);
VERIFY_IS_NOT_NULL(p1);
VERIFY_IS_NOT_NULL(p2);
p1->WindowName(L"one");
p2->WindowName(L"two");
VERIFY_ARE_EQUAL(0, p1->GetID());
VERIFY_ARE_EQUAL(0, p2->GetID());
m0->AddPeasant(*p1);
m0->AddPeasant(*p2);
VERIFY_ARE_EQUAL(1, p1->GetID());
VERIFY_ARE_EQUAL(2, p2->GetID());
VERIFY_ARE_EQUAL(2u, m0->_peasants.size());
VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"one"));
VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));
Log::Comment(L"Kill peasant 1. Make sure that it gets removed from the monarch.");
RemotingTests::_killPeasant(m0, p1->GetID());
// By killing 1, then looking for "two", we happen to iterate over the
// corpse of 1 when looking for the peasant named "two". This causes us
// to remove 1 while looking for "two". Technically, we shouldn't be
// relying on any sort of ordering for an unordered_map iterator, but
// this one just so happens to work.
VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));
Log::Comment(L"Peasant 1 should have been pruned");
VERIFY_ARE_EQUAL(1u, m0->_peasants.size());
}
void RemotingTests::LookupNamedPeasantWhenItDied()
{
Log::Comment(L"Test that looking up a dead peasant by name returns 0, "
L"indicating there's no peasant with that name.");
const auto monarch0PID = 12345u;
const auto peasant1PID = 23456u;
const auto peasant2PID = 34567u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
com_ptr<Remoting::implementation::Peasant> p2;
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
VERIFY_IS_NOT_NULL(m0);
VERIFY_IS_NOT_NULL(p1);
VERIFY_IS_NOT_NULL(p2);
p1->WindowName(L"one");
p2->WindowName(L"two");
VERIFY_ARE_EQUAL(0, p1->GetID());
VERIFY_ARE_EQUAL(0, p2->GetID());
m0->AddPeasant(*p1);
m0->AddPeasant(*p2);
VERIFY_ARE_EQUAL(1, p1->GetID());
VERIFY_ARE_EQUAL(2, p2->GetID());
VERIFY_ARE_EQUAL(2u, m0->_peasants.size());
VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"one"));
VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));
Log::Comment(L"Kill peasant 1. Make sure that it gets removed from the monarch.");
RemotingTests::_killPeasant(m0, p1->GetID());
VERIFY_ARE_EQUAL(0, m0->_lookupPeasantIdForName(L"one"));
Log::Comment(L"Peasant 1 should have been pruned");
VERIFY_ARE_EQUAL(1u, m0->_peasants.size());
VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));
}
void RemotingTests::GetMruPeasantAfterNameLookupForDeadPeasant()
{
// This test is trying to hit the catch in Monarch::_lookupPeasantIdForName.
//
// We need to:
// * add some peasants,
// * make one the mru, then make a named two the mru
// * then kill two
// * then try to get the mru peasant -> it should be one
const winrt::guid guid1{ Utils::GuidFromString(L"{11111111-1111-1111-1111-111111111111}") };
const auto monarch0PID = 12345u;
const auto peasant1PID = 23456u;
const auto peasant2PID = 34567u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
com_ptr<Remoting::implementation::Peasant> p2;
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
VERIFY_IS_NOT_NULL(m0);
VERIFY_IS_NOT_NULL(p1);
VERIFY_IS_NOT_NULL(p2);
p1->WindowName(L"one");
p2->WindowName(L"two");
VERIFY_ARE_EQUAL(0, p1->GetID());
VERIFY_ARE_EQUAL(0, p2->GetID());
m0->AddPeasant(*p1);
m0->AddPeasant(*p2);
VERIFY_ARE_EQUAL(1, p1->GetID());
VERIFY_ARE_EQUAL(2, p2->GetID());
VERIFY_ARE_EQUAL(2u, m0->_peasants.size());
VERIFY_ARE_EQUAL(p1->GetID(), m0->_lookupPeasantIdForName(L"one"));
VERIFY_ARE_EQUAL(p2->GetID(), m0->_lookupPeasantIdForName(L"two"));
{
Log::Comment(L"Activate the first peasant, first desktop");
Remoting::WindowActivatedArgs activatedArgs{ p1->GetID(),
guid1,
winrt::clock().now() };
p1->ActivateWindow(activatedArgs);
}
{
Log::Comment(L"Activate the second peasant, first desktop");
Remoting::WindowActivatedArgs activatedArgs{ p2->GetID(),
guid1,
winrt::clock().now() };
p2->ActivateWindow(activatedArgs);
}
Log::Comment(L"Kill peasant 2.");
RemotingTests::_killPeasant(m0, p2->GetID());
VERIFY_ARE_EQUAL(p1->GetID(), m0->_getMostRecentPeasantID(false));
VERIFY_ARE_EQUAL(p1->GetID(), m0->_getMostRecentPeasantID(true));
}
void RemotingTests::ProposeCommandlineForNamedDeadWindow()
{
Log::Comment(L"Test proposing a commandline for a named window that's "
L"currently dead. This should result in a new window with "
L"the given name.");
const auto monarch0PID = 12345u;
const auto peasant1PID = 23456u;
const auto peasant2PID = 34567u;
com_ptr<Remoting::implementation::Monarch> m0;
m0.attach(new Remoting::implementation::Monarch(monarch0PID));
VERIFY_IS_NOT_NULL(m0);
m0->FindTargetWindowRequested(&RemotingTests::_findTargetWindowByNameHelper);
com_ptr<Remoting::implementation::Peasant> p1;
p1.attach(new Remoting::implementation::Peasant(peasant1PID));
com_ptr<Remoting::implementation::Peasant> p2;
p2.attach(new Remoting::implementation::Peasant(peasant2PID));
VERIFY_IS_NOT_NULL(m0);
VERIFY_IS_NOT_NULL(p1);
VERIFY_IS_NOT_NULL(p2);
p1->WindowName(L"one");
p2->WindowName(L"two");
VERIFY_ARE_EQUAL(0, p1->GetID());
VERIFY_ARE_EQUAL(0, p2->GetID());
p1->ExecuteCommandlineRequested([&](auto&&, const Remoting::CommandlineArgs& cmdlineArgs) {
Log::Comment(L"Commandline dispatched to p1");
VERIFY_IS_GREATER_THAN(cmdlineArgs.Commandline().size(), 1u);
VERIFY_ARE_EQUAL(L"arg[1]", cmdlineArgs.Commandline().at(1));
});
p2->ExecuteCommandlineRequested([&](auto&&, const Remoting::CommandlineArgs& cmdlineArgs) {
Log::Comment(L"Commandline dispatched to p2");
VERIFY_IS_GREATER_THAN(cmdlineArgs.Commandline().size(), 1u);
VERIFY_ARE_EQUAL(L"this is for p2", cmdlineArgs.Commandline().at(1));
});
p1->WindowName(L"one");
p2->WindowName(L"two");
m0->AddPeasant(*p1);
m0->AddPeasant(*p2);
std::vector<winrt::hstring> p1Args{ L"one", L"arg[1]" };
std::vector<winrt::hstring> p2Args{ L"two", L"this is for p2" };
{
Remoting::CommandlineArgs eventArgs{ { p1Args }, { L"" } };
auto result = m0->ProposeCommandline(eventArgs);
VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow());
VERIFY_ARE_EQUAL(false, (bool)result.Id()); // Casting to (bool) checks if the reference has a value
VERIFY_ARE_EQUAL(L"", result.WindowName());
}
{
Log::Comment(L"Send a commandline to \"two\", which should be p2");
Remoting::CommandlineArgs eventArgs{ { p2Args }, { L"" } };
auto result = m0->ProposeCommandline(eventArgs);
VERIFY_ARE_EQUAL(false, result.ShouldCreateWindow());
VERIFY_ARE_EQUAL(false, (bool)result.Id()); // Casting to (bool) checks if the reference has a value
VERIFY_ARE_EQUAL(L"", result.WindowName());
}
Log::Comment(L"Kill peasant 2.");
RemotingTests::_killPeasant(m0, p2->GetID());
{
Log::Comment(L"Send a commandline to \"two\", who is now dead.");
Remoting::CommandlineArgs eventArgs{ { p2Args }, { L"" } };
auto result = m0->ProposeCommandline(eventArgs);
VERIFY_ARE_EQUAL(true, result.ShouldCreateWindow());
VERIFY_ARE_EQUAL(false, (bool)result.Id()); // Casting to (bool) checks if the reference has a value
VERIFY_ARE_EQUAL(L"two", result.WindowName());
}
}
Add `Microsoft.Terminal.Remoting.dll` (#8607) Adds a `Microsoft.Terminal.Remoting.dll` to our solution. This DLL will be responsible for all the Monarch/Peasant work that's been described in #7240 & #8135. This PR does _not_ implement the Monarch/Peasant architecture in any significant way. The goal of this PR is to just to establish the project layout, and the most basic connections. This should make reviewing the actual meat of the implementation (in a later PR) easier. It will also give us the opportunity to include some of the basic weird things we're doing (with `CoRegisterClass`) in the Terminal _now_, and get them selfhosted, before building on them too much. This PR does have windows registering the `Monarch` class with COM. When windows are created, they'll as the Monarch if they should create a new window or not. In this PR, the Monarch will always reply "yes, please make a new window". Similar to other projects in our solution, we're adding 3 projects here: * `Microsoft.Terminal.Remoting.lib`: the actual implementation, as a static lib. * `Microsoft.Terminal.Remoting.dll`: The implementation linked as a DLL, for use in `WindowsTerminal.exe`. * `Remoting.UnitTests.dll`: A unit test dll that links with the static lib. There are plenty of TODOs scattered about the code. Clearly, most of this isn't implemented yet, but I do have more WIP branches. I'm using [`projects/5`](https://github.com/microsoft/terminal/projects/5) as my notation for TODOs that are too small for an issue, but are part of the whole Process Model 2.0 work. ## References * #5000 - this is the process model megathread * #7240 - The process model 2.0 spec. * #8135 - the window management spec. (please review me, I have 0/3 signoffs even after the discussion we had 😢) * #8171 - the Monarch/peasant sample. (please review me, I have 1/2) ## PR Checklist * [x] Closes nothing, this is just infrastructure * [x] I work here * [x] Tests added/passed * [n/a] Requires documentation to be updated
2021-01-07 23:59:37 +01:00
}