Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use CPS for tests where saving documents needs to be reliable #70983

Merged
merged 15 commits into from
Dec 28, 2023

Conversation

sharwell
Copy link
Member

@sharwell sharwell commented Nov 28, 2023

This is generally a workaround for #70938.

  • Use CPS for projects where saving documents needs to be reliable.
  • Use full path for setting breakpoints in integration tests. This would be significantly improved by rewriting the breakpoint code to open documents and set breakpoints in the same manner as a user, but for now it uses DTE in a manner that appears to now work for CPS.
  • Log MEF composition errors when tests fail.
  • Collect animated screenshots of the test execution when tests fail.

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Infrastructure untriaged Issues and PRs which have not yet been triaged by a lead labels Nov 28, 2023
@Cosifne
Copy link
Member

Cosifne commented Dec 7, 2023

When will this be ready to review? 🙂

@sharwell sharwell marked this pull request as ready for review December 8, 2023 17:04
@sharwell sharwell requested review from a team as code owners December 8, 2023 17:04
@sharwell
Copy link
Member Author

sharwell commented Dec 8, 2023

@Cosifne it should be ready now

Copy link
Member

@jasonmalinowski jasonmalinowski left a comment

Choose a reason for hiding this comment

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

Overall loving the approach, just had a bunch of specific questions and suggestions.

if (s_editorPackage is null)
return;

var folder = s_editorPackage.UserLocalDataPath;
Copy link
Member

Choose a reason for hiding this comment

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

Why are we asking the editor package for this versus just calling one of the other APIs for this same path?

Copy link
Contributor

Choose a reason for hiding this comment

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

Would love to learn about APIs that might exist for getting the right path here. I wrote a rather brute force approach in Razor to do it, which I've always wondered when it might break: https://github.com/dotnet/razor/blob/main/src/Razor/test/Microsoft.VisualStudio.Razor.IntegrationTests/VisualStudioLogging.cs#L134

Copy link
Member Author

Choose a reason for hiding this comment

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

➡️ I now obtain the path from IVsComponentModelHost

}
catch (Exception ex)
{
content = ex.ToString();
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
content = ex.ToString();
content = $"Exception thrown while reading {file}: {ex}";

So it's more clear this the content of the file in that case.

Copy link
Member Author

Choose a reason for hiding this comment

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

➡️ Now updated

namespace Roslyn.VisualStudio.NewIntegrationTests.InProcess;

[TestService]
internal partial class ScreenshotInProcess
Copy link
Member

Choose a reason for hiding this comment

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

You might want to add a one-or-two sentence comment here just to say "this takes screenshots and saves them as an .apng" and link to the spec. Mostly because somebody who sees this code who doesn't know what did here first would go "what is this???"

Copy link
Member Author

Choose a reason for hiding this comment

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

➡️ Comments added

DataCollectionService.RegisterCustomLogger(
static fullPath =>
{
lock (s_frames)
Copy link
Member

Choose a reason for hiding this comment

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

Add a comment to s_frames that we're taking locks this way. (No concerns that we are, but is still good to make it clear.)

Copy link
Member Author

Choose a reason for hiding this comment

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

➡️ Comment added

Comment on lines +131 to +132
if (s_frames.Count == 0)
return;
Copy link
Member

Choose a reason for hiding this comment

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

Given we're going to add a frame at the end, why skip this? I could imagine if something fails really catastrophically the last/only frame might still be useful?

Copy link
Member Author

@sharwell sharwell Dec 15, 2023

Choose a reason for hiding this comment

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

➡️ We already capture the final screenshot as a .png (built-in feature of the harness)

Comment on lines +499 to +502
Application.Current.MainWindow.LayoutUpdated -= OnThrottledInteraction;
Application.Current.MainWindow.PreviewMouseMove -= OnThrottledInteraction;
Application.Current.MainWindow.PreviewMouseDown -= OnInteraction;
Application.Current.MainWindow.PreviewKeyDown -= OnInteraction;
Copy link
Member

Choose a reason for hiding this comment

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

What might be useful is if the images captured for the key actions would also write to the picture which key was being pressed.

Copy link
Member

Choose a reason for hiding this comment

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

(this can of course be a follow up!)

Copy link
Member Author

@sharwell sharwell Dec 27, 2023

Choose a reason for hiding this comment

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

➡️ Yes, there are a few potential improvements like this. I think the most important early improvement would be frame differencing/cropping to reduce the output size.

Comment on lines +480 to +483
lock (s_frames)
{
s_frames.Clear();
}
Copy link
Member

Choose a reason for hiding this comment

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

Why clearing if a one-off capture fails? Maybe instead write a black frame or something so a transient failure is understood to be transient?

Copy link
Member Author

@sharwell sharwell Dec 15, 2023

Choose a reason for hiding this comment

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

➡️ InitializeCoreAsync is called at the start of a new test. It would be misleading to preserve frames from a prior test here.

Contract.ThrowIfTrue(idat.Count == 0);
Contract.ThrowIfTrue(iend.IsEmpty);

return (signature, ihdr, srgb, gama, phys, idat.ToImmutableArrayOrEmpty(), iend);
Copy link
Member

Choose a reason for hiding this comment

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

Why are we returning a bunch of spans we just asserted are empty?

Copy link
Member Author

@sharwell sharwell Dec 15, 2023

Choose a reason for hiding this comment

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

➡️ We asserted they are not empty.

static ScreenshotInProcess()
{
DataCollectionService.RegisterCustomLogger(
static fullPath =>
Copy link
Member

Choose a reason for hiding this comment

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

What value would be passed as fullPath? If multiple tests fail will they have clear different names in CI?

Copy link
Member Author

Choose a reason for hiding this comment

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

➡️ The full path is determined by the test harness. The test name is part of the full path, so outputs from different tests can generally be identified. There are some exceptions (e.g. theories where inputs change but the test has the same name), but improvements in this space would be owned by microsoft/vs-extension-testing.

var firstEncoded = EncodeFrame(firstFrame);

// PNG Signature (8 bytes)
WritePngSignature(fileStream, buffer);
Copy link
Member

Choose a reason for hiding this comment

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

A unrelated question:
Why choose APNG instead of Gif?

Copy link
Member Author

@sharwell sharwell Dec 15, 2023

Choose a reason for hiding this comment

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

➡️ PNG preserves the full image quality and seemed easy

Over = 1,
}

static ScreenshotInProcess()
Copy link
Member

Choose a reason for hiding this comment

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

If I run the test locally, will it also record the screen?

Copy link
Member

Choose a reason for hiding this comment

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

Also, does it only collect when test fails? (I didn't see the change, did you make any thing in the extension package?)

Copy link
Member Author

@sharwell sharwell Dec 15, 2023

Choose a reason for hiding this comment

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

If I run the test locally, will it also record the screen?

Yes

Also, does it only collect when test fails?

➡️ No, but it only saves to disk when the test fails

@sharwell
Copy link
Member Author

@Cosifne @jasonmalinowski @davidwengier I believe all feedback responded to now

goto case HotReloadAction.Edit;

case HotReloadAction.Edit:
//if (!isManaged)
Copy link
Member

@Cosifne Cosifne Dec 28, 2023

Choose a reason for hiding this comment

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

Do we want to keep these commented code?

Copy link
Member

Choose a reason for hiding this comment

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

Also there are commented code in other cases.

Copy link
Member Author

Choose a reason for hiding this comment

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

➡️ Yes (keep), mainly because if we ever need these, the text in the comment gives something to search for the reference implementation.

<Name>VisualStudioSetup</Name>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\..\..\ExpressionEvaluator\Package\ExpressionEvaluatorPackage.csproj" Name="ExpressionEvaluatorPackage" Private="false" />
Copy link
Member

Choose a reason for hiding this comment

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

Why it needs to reference ExpressionEvaluator pacakge now?

Copy link
Member Author

Choose a reason for hiding this comment

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

➡️ It was always needed, but we forgot it previously.

Copy link
Member

@Cosifne Cosifne left a comment

Choose a reason for hiding this comment

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

LGTM. only have some nits comments and questions in the project file.

@sharwell
Copy link
Member Author

Merging to improve stability and diagnosabliity of integration tests. @jasonmalinowski if you have any other questions please feel free to reach out for follow-up.

@sharwell sharwell merged commit a5daa7d into dotnet:main Dec 28, 2023
31 checks passed
@ghost ghost added this to the Next milestone Dec 28, 2023
@sharwell sharwell deleted the use-cps-2 branch December 28, 2023 21:48
@Cosifne Cosifne modified the milestones: Next, 17.9 P3 Jan 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Infrastructure untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants