@@ -11,51 +11,121 @@ namespace Microsoft.Diagnostics.NETCore.Client
1111{
1212 public class GetProcessInfoTests
1313 {
14- private readonly ITestOutputHelper output ;
14+ private readonly ITestOutputHelper _output ;
1515
1616 public GetProcessInfoTests ( ITestOutputHelper outputHelper )
1717 {
18- output = outputHelper ;
18+ _output = outputHelper ;
1919 }
2020
2121 [ Fact ]
22- public Task BasicProcessInfoTest ( )
22+ public Task BasicProcessInfoNoSuspendTest ( )
2323 {
24- return BasicProcessInfoTestCore ( useAsync : false ) ;
24+ return BasicProcessInfoTestCore ( useAsync : false , suspend : false ) ;
2525 }
2626
2727 [ Fact ]
28- public Task BasicProcessInfoTestAsync ( )
28+ public Task BasicProcessInfoNoSuspendTestAsync ( )
2929 {
30- return BasicProcessInfoTestCore ( useAsync : true ) ;
30+ return BasicProcessInfoTestCore ( useAsync : true , suspend : false ) ;
3131 }
3232
33- private async Task BasicProcessInfoTestCore ( bool useAsync )
33+ [ Fact ]
34+ public Task BasicProcessInfoSuspendTest ( )
35+ {
36+ return BasicProcessInfoTestCore ( useAsync : false , suspend : true ) ;
37+ }
38+
39+ [ Fact ]
40+ public Task BasicProcessInfoSuspendTestAsync ( )
41+ {
42+ return BasicProcessInfoTestCore ( useAsync : true , suspend : true ) ;
43+ }
44+
45+ private async Task BasicProcessInfoTestCore ( bool useAsync , bool suspend )
3446 {
35- using TestRunner runner = new TestRunner ( CommonHelper . GetTraceePathWithArgs ( targetFramework : "net5.0" ) , output ) ;
47+ using TestRunner runner = new TestRunner ( CommonHelper . GetTraceePathWithArgs ( targetFramework : "net5.0" ) , _output ) ;
48+ if ( suspend )
49+ {
50+ runner . SuspendDefaultDiagnosticPort ( ) ;
51+ }
3652 runner . Start ( ) ;
3753
3854 try
3955 {
4056 DiagnosticsClientApiShim clientShim = new DiagnosticsClientApiShim ( new DiagnosticsClient ( runner . Pid ) , useAsync ) ;
4157
42- ProcessInfo processInfo = await clientShim . GetProcessInfo ( ) ;
58+ // While suspended, the runtime will not provide entrypoint information.
59+ if ( suspend )
60+ {
61+ ProcessInfo processInfoBeforeResume = await clientShim . GetProcessInfo ( ) ;
62+ ValidateProcessInfo ( runner . Pid , processInfoBeforeResume ) ;
63+ Assert . True ( string . IsNullOrEmpty ( processInfoBeforeResume . ManagedEntrypointAssemblyName ) ) ;
4364
44- Assert . NotNull ( processInfo ) ;
45- Assert . Equal ( runner . Pid , ( int ) processInfo . ProcessId ) ;
46- Assert . NotNull ( processInfo . CommandLine ) ;
47- Assert . NotNull ( processInfo . OperatingSystem ) ;
48- Assert . NotNull ( processInfo . ProcessArchitecture ) ;
49- //Assert.Equal("Tracee", processInfo.ManagedEntrypointAssemblyName );
50- //Version clrVersion = ParseVersionRemoveLabel(processInfo.ClrProductVersionString );
51- // Assert.True(clrVersion >= new Version(6, 0, 0) );
65+ await clientShim . ResumeRuntime ( ) ;
66+ }
67+
68+ // The entrypoint information is available some short time after the runtime
69+ // begins to execute. Retry getting process information until entrypoint is available.
70+ ProcessInfo processInfo = await GetProcessInfoWithEntrypointAsync ( clientShim ) ;
71+ ValidateProcessInfo ( runner . Pid , processInfo ) ;
72+ Assert . Equal ( "Tracee" , processInfo . ManagedEntrypointAssemblyName ) ;
5273 }
5374 finally
5475 {
5576 runner . PrintStatus ( ) ;
5677 }
5778 }
5879
80+ /// <summary>
81+ /// Get process information with entrypoint information with exponential backoff on retries.
82+ /// </summary>
83+ private async Task < ProcessInfo > GetProcessInfoWithEntrypointAsync ( DiagnosticsClientApiShim shim )
84+ {
85+ int retryMilliseconds = 5 ;
86+ int currentAttempt = 1 ;
87+ const int maxAttempts = 10 ;
88+
89+ _output . WriteLine ( "Getting process info with entrypoint:" ) ;
90+ while ( currentAttempt <= maxAttempts )
91+ {
92+ _output . WriteLine ( "- Attempt {0} of {1}." , currentAttempt , maxAttempts ) ;
93+
94+ ProcessInfo processInfo = await shim . GetProcessInfo ( ) ;
95+ Assert . NotNull ( processInfo ) ;
96+
97+ if ( ! string . IsNullOrEmpty ( processInfo . ManagedEntrypointAssemblyName ) )
98+ {
99+ _output . WriteLine ( "Got process info with entrypoint." ) ;
100+ return processInfo ;
101+ }
102+
103+ currentAttempt ++ ;
104+
105+ if ( currentAttempt != maxAttempts )
106+ {
107+ _output . WriteLine ( " Waiting {0} ms." , retryMilliseconds ) ;
108+
109+ await Task . Delay ( retryMilliseconds ) ;
110+
111+ retryMilliseconds = Math . Min ( 2 * retryMilliseconds , 500 ) ;
112+ }
113+ }
114+
115+ throw new InvalidOperationException ( "Unable to get process info with entrypoint." ) ;
116+ }
117+
118+ private static void ValidateProcessInfo ( int expectedProcessId , ProcessInfo processInfo )
119+ {
120+ Assert . NotNull ( processInfo ) ;
121+ Assert . Equal ( expectedProcessId , ( int ) processInfo . ProcessId ) ;
122+ Assert . NotNull ( processInfo . CommandLine ) ;
123+ Assert . NotNull ( processInfo . OperatingSystem ) ;
124+ Assert . NotNull ( processInfo . ProcessArchitecture ) ;
125+ Version clrVersion = ParseVersionRemoveLabel ( processInfo . ClrProductVersionString ) ;
126+ Assert . True ( clrVersion >= new Version ( 6 , 0 , 0 ) ) ;
127+ }
128+
59129 private static Version ParseVersionRemoveLabel ( string versionString )
60130 {
61131 Assert . NotNull ( versionString ) ;
0 commit comments