Skip to content

Further work to stabilize the integration test interop layer#25455

Merged
sharwell merged 8 commits intodotnet:dev15.7.xfrom
sharwell:com-message-filter
Mar 31, 2018
Merged

Further work to stabilize the integration test interop layer#25455
sharwell merged 8 commits intodotnet:dev15.7.xfrom
sharwell:com-message-filter

Conversation

@sharwell
Copy link
Copy Markdown
Contributor

@sharwell sharwell commented Mar 13, 2018

  • Use IMessageFilter for consistent COM retry semantics
  • Make DebugAssertFailureException serializable
  • Avoid manual message pumping in HostWaitHelper
  • Initial work to retry UI automation calls if/when they fail with UIA_E_ELEMENTNOTAVAILABLE
  • Make ThrowingTraceListener use InvalidOperationException instead of DebugAssertFailureException

@sharwell sharwell added the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label Mar 13, 2018
@sharwell sharwell requested a review from a team as a code owner March 13, 2018 23:30
@sharwell sharwell force-pushed the com-message-filter branch 2 times, most recently from 6ef54ea to a4e53e7 Compare March 14, 2018 02:43
@sharwell sharwell force-pushed the com-message-filter branch from a4e53e7 to 08fee02 Compare March 29, 2018 16:37
@sharwell sharwell changed the title [WIP] Further work to stabilize the integration test interop layer Further work to stabilize the integration test interop layer Mar 30, 2018
@sharwell
Copy link
Copy Markdown
Contributor Author

sharwell commented Mar 30, 2018

Looks like 54330a6 only fixed half the problem with figuring out what exception is thrown.

Before my change we got this exception:

System.Runtime.Serialization.SerializationException: Type 'Microsoft.CodeAnalysis.ThrowingTraceListener+DebugAssertFailureException' in Assembly 'Roslyn.Test.Utilities, Version=42.42.42.42, Culture=neutral, PublicKeyToken=fc793a00266884fb' is not marked as serializable.
   at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder)
   at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder)
   at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck)
   at System.Runtime.Remoting.Channels.CrossAppDomainSerializer.SerializeObject(Object obj, MemoryStream stm)
   at System.AppDomain.Serialize(Object o)
   at System.AppDomain.MarshalObject(Object o)

After my change in 54330a6 we got this exception:

System.Runtime.Serialization.SerializationException: Unable to find assembly 'Roslyn.Test.Utilities, Version=42.42.42.42, Culture=neutral, PublicKeyToken=fc793a00266884fb'.
   at System.Runtime.Serialization.Formatters.Binary.BinaryAssemblyInfo.GetAssembly()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.GetType(BinaryAssemblyInfo assemblyInfo, String name)
   at System.Runtime.Serialization.Formatters.Binary.ObjectMap..ctor(String objectName, String[] memberNames, BinaryTypeEnum[] binaryTypeEnumA, Object[] typeInformationA, Int32[] memberAssemIds, ObjectReader objectReader, Int32 objectId, BinaryAssemblyInfo assemblyInfo, SizedArray assemIdToAssemblyTable)
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.ReadObjectWithMapTyped(BinaryObjectWithMapTyped record)
   at System.Runtime.Serialization.Formatters.Binary.__BinaryParser.Run()
   at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
   at System.Runtime.Remoting.Channels.CrossAppDomainSerializer.DeserializeObject(MemoryStream stm)
   at System.AppDomain.Deserialize(Byte[] blob)
   at System.AppDomain.UnmarshalObject(Byte[] blob)

Now I've switch to just using InvalidOperationException.

@sharwell sharwell removed the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label Mar 30, 2018
@sharwell sharwell changed the base branch from dev15.7.x to dev15.7.x-vs-deps March 30, 2018 22:18
@sharwell sharwell changed the base branch from dev15.7.x-vs-deps to dev15.7.x March 30, 2018 22:18

private static void RetryIfNotAvailable<T>(Action<T> action, T state)
{
for (var i = 0; true; i++)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

true [](start = 28, length = 4)

I'd rather you make this explicitly i < AutomationRetryCount, and throw an unreachable exception after the try/catch. It took me a minute of verifying exit conditions to actually be sure this wasn't an infinite loop, and that pattern will much easier to reason about your expectations.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

💭 The issue I encountered here is it doesn't change the way the exception filter is used, so technically such a change would increase the cyclomatic complexity of the method but not actually add any reachable paths.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It might increase some complexity of the method, but imo would result in code that is more easily understandable and verifiable.


In reply to: 178400103 [](ancestors = 178400103)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

➡️ I went with a documentation approach instead. Hopefully it's enough to make it reasonably clear.

var view = GetActiveTextView();
var broker = GetComponentModel().GetService<ILightBulbBroker>();
return GetLightBulbActions(broker, view).Select(a => a.DisplayText).ToArray();
return (await GetLightBulbActionsAsync(broker, view)).Select(a => a.DisplayText).ToArray();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Missing a few explicit ConfigureAwaits in this file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added

if (blockUntilComplete)
{
BeginInvokeExecuteOnActiveView(lightBulbAction);
task.Join();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is there a way to add an assert here that we're not currently on the main thread?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

➡️ This is JoinableTask.Join; there is no caller affinity restriction.

Copy link
Copy Markdown
Member

@333fred 333fred left a comment

Choose a reason for hiding this comment

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

Done review (Iteration 6).

The implementations of ISuggestedAction use threading assertions instead of
automatic transition to the correct thread, placing the burden of correct
thread selection on the caller, TextViewWindow_InProc. This change switches
to the vs-threading approach for maintaining thread affinity, which has two
parts:

1. When entering thread-affinitized code, switch to the correct thread
2. Avoid using ConfigureAwait(false) to lose the required affinity

The entire file relies on the default behavior of ConfigureAwait, which is
the normal coding practice in asynchronous code following vs-threading
patterns.
@sharwell
Copy link
Copy Markdown
Contributor Author

sharwell commented Mar 31, 2018

💭 Failure in CSharpCodeActions.GenerateMethodInClosedFile looks a code action is incorrectly reporting that it has no changes to apply (empty preview).
https://ci.dot.net/job/dotnet_roslyn/job/dev15.7.x/job/windows_debug_vs-integration_prtest/266/

    Roslyn.VisualStudio.IntegrationTests.CSharp.CSharpCodeActions.GenerateMethodInClosedFile
      Assert.Equal() Failure
                    ↓ (pos 2)
      Expected: \r\nusing System;\r\n\r\npublic class Foo\r\n{\r\n   ···
      Actual:   \r\npublic class Foo\r\n{\r\n}\r\n
                    ↑ (pos 2)
      Stack Trace:
           at Microsoft.VisualStudio.IntegrationTest.Utilities.OutOfProcess.SolutionExplorer_OutOfProc.Verifier.FileContents(Project project, String fileName, String expectedContents)
           at Roslyn.VisualStudio.IntegrationTests.CSharp.CSharpCodeActions.GenerateMethodInClosedFile()

image

@sharwell
Copy link
Copy Markdown
Contributor Author

Merging this test-only change to unblock ongoing test stabilization work. I alerted @333fred to the change in ba524a7 (which reverts something he requested in review) and we can review alternatives in the upcoming week if a change needs to be made.

@sharwell sharwell merged commit b45fa2d into dotnet:dev15.7.x Mar 31, 2018
@sharwell sharwell deleted the com-message-filter branch March 31, 2018 14:27
sharwell added a commit to sharwell/MouseFastScroll that referenced this pull request May 1, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants