@@ -19,7 +19,6 @@ public class CollectCommandFunctionalTests
1919 private const string ExpectedPayload = "CollectCommandFunctionalTestsTraceData" ;
2020
2121 public sealed record CollectArgs (
22- FileInfo output ,
2322 CancellationToken ct = default ,
2423 CommandLineConfiguration cliConfig = null ,
2524 int processId = - 1 ,
@@ -41,8 +40,8 @@ public sealed record CollectArgs(
4140 string dsrouter = "" )
4241 {
4342 internal TraceFileFormat Format => ( TraceFileFormat ) formatValue ;
44- public string OutputFilePath => output . FullName ;
4543 public int ProcessId => processId == - 1 ? Environment . ProcessId : processId ;
44+ public FileInfo Output => new FileInfo ( "trace.nettrace" ) ;
4645 private MemoryStream _eventStream = new ( ) ;
4746 public MemoryStream EventStream => _eventStream ;
4847 }
@@ -51,7 +50,7 @@ public sealed record CollectArgs(
5150 [ MemberData ( nameof ( BasicCases ) ) ]
5251 public async Task CollectCommandProviderConfigurationConsolidation ( CollectArgs args , string [ ] expectedSubset )
5352 {
54- MockConsole console = new ( 200 , 30 ) ;
53+ MockConsole console = new ( 200 , 30 ) { IsOutputRedirected = false } ;
5554 string [ ] rawLines = await RunAsync ( args , console ) . ConfigureAwait ( true ) ;
5655 console . AssertSanitizedLinesEqual ( CollectSanitizer , expectedSubset ) ;
5756
@@ -64,16 +63,15 @@ private static async Task<string[]> RunAsync(CollectArgs config, MockConsole con
6463 var handler = new CollectCommandHandler ( ) ;
6564 handler . StartTraceSessionAsync = ( client , cfg , ct ) => Task . FromResult < CollectCommandHandler . ICollectSession > ( new TestCollectSession ( ) ) ;
6665 handler . ResumeRuntimeAsync = ( client , ct ) => Task . CompletedTask ;
67- handler . CursorOperationsSupported = false ;
68- handler . CollectSessionEventStream = ( name ) => config . EventStream ;
66+ handler . CollectSessionEventStream = ( name ) => new SlowSinkStream ( config . EventStream ) ;
6967 handler . Console = console ;
70- handler . IsOutputRedirected = false ;
68+ handler . FileSizeForStatus = Encoding . UTF8 . GetByteCount ( ExpectedPayload ) ;
7169
7270 int exit = await handler . Collect (
7371 config . ct ,
7472 config . cliConfig ,
7573 config . ProcessId ,
76- config . output ,
74+ config . Output ,
7775 config . buffersize ,
7876 config . providers ,
7977 config . profile ,
@@ -98,6 +96,32 @@ private static async Task<string[]> RunAsync(CollectArgs config, MockConsole con
9896 return console . Lines ;
9997 }
10098
99+ // As the test payload is small, we need to delay writes to the output stream to ensure
100+ // that the status update logic in CollectCommandHandler has a chance to run.
101+ private sealed class SlowSinkStream : Stream
102+ {
103+ private readonly Stream _inner ;
104+
105+ public SlowSinkStream ( Stream inner ) { _inner = inner ; }
106+
107+ public override bool CanRead => false ;
108+ public override bool CanSeek => false ;
109+ public override bool CanWrite => true ;
110+ public override long Length => throw new NotSupportedException ( ) ;
111+ public override long Position { get => throw new NotSupportedException ( ) ; set => throw new NotSupportedException ( ) ; }
112+
113+ public override void Flush ( ) { }
114+ public override int Read ( byte [ ] buffer , int offset , int count ) => throw new NotSupportedException ( ) ;
115+ public override long Seek ( long offset , SeekOrigin origin ) => throw new NotSupportedException ( ) ;
116+ public override void SetLength ( long value ) => throw new NotSupportedException ( ) ;
117+ public override void Write ( byte [ ] buffer , int offset , int count ) => _inner . Write ( buffer , offset , count ) ;
118+ public override async Task WriteAsync ( byte [ ] buffer , int offset , int count , CancellationToken cancellationToken )
119+ {
120+ await Task . Delay ( 200 , cancellationToken ) . ConfigureAwait ( false ) ;
121+ await _inner . WriteAsync ( buffer , offset , count , cancellationToken ) . ConfigureAwait ( false ) ;
122+ }
123+ }
124+
101125 private static string [ ] CollectSanitizer ( string [ ] lines )
102126 {
103127 List < string > result = new ( ) ;
@@ -107,6 +131,10 @@ private static string[] CollectSanitizer(string[] lines)
107131 {
108132 result . Add ( "Process : <PROCESS>" ) ;
109133 }
134+ else if ( line . StartsWith ( '[' ) && line . Contains ( "Recording trace" ) )
135+ {
136+ result . Add ( "[dd:hh:mm:ss]\t " + line . Substring ( 14 ) ) ;
137+ }
110138 else
111139 {
112140 result . Add ( line ) ;
@@ -126,11 +154,11 @@ public void Stop() {}
126154
127155 public static IEnumerable < object [ ] > BasicCases ( )
128156 {
157+ FileInfo fi = new ( "trace.nettrace" ) ;
129158 yield return new object [ ]
130159 {
131- new CollectArgs ( output : new FileInfo ( "noProviders" ) ) ,
160+ new CollectArgs ( ) ,
132161 ExpectProvidersWithMessages (
133- "noProviders" ,
134162 new [ ]
135163 {
136164 "No profile or providers specified, defaulting to trace profile 'cpu-sampling'"
@@ -141,45 +169,40 @@ public static IEnumerable<object[]> BasicCases()
141169
142170 yield return new object [ ]
143171 {
144- new CollectArgs ( output : new FileInfo ( "singleProvider" ) , providers : "Foo:0x1:4" ) ,
172+ new CollectArgs ( providers : "Foo:0x1:4" ) ,
145173 ExpectProviders (
146- "singleProvider" ,
147174 FormatProvider ( "Foo" , "0000000000000001" , "Informational" , 4 , "--providers" ) )
148175 } ;
149176
150177 yield return new object [ ]
151178 {
152- new CollectArgs ( output : new FileInfo ( "multipleProviders" ) , providers : "Foo:0x1:4,Bar:0x2:4" ) ,
179+ new CollectArgs ( providers : "Foo:0x1:4,Bar:0x2:4" ) ,
153180 ExpectProviders (
154- "multipleProviders" ,
155181 FormatProvider ( "Foo" , "0000000000000001" , "Informational" , 4 , "--providers" ) ,
156182 FormatProvider ( "Bar" , "0000000000000002" , "Informational" , 4 , "--providers" ) )
157183 } ;
158184
159185 yield return new object [ ]
160186 {
161- new CollectArgs ( output : new FileInfo ( "profileOnly" ) , profile : "cpu-sampling" ) ,
187+ new CollectArgs ( profile : "cpu-sampling" ) ,
162188 ExpectProviders (
163- "profileOnly" ,
164189 FormatProvider ( "Microsoft-DotNETCore-SampleProfiler" , "0000F00000000000" , "Informational" , 4 , "--profile" ) ,
165190 FormatProvider ( "Microsoft-Windows-DotNETRuntime" , "00000014C14FCCBD" , "Informational" , 4 , "--profile" ) )
166191 } ;
167192
168193 yield return new object [ ]
169194 {
170- new CollectArgs ( output : new FileInfo ( "profileAndProviders" ) , profile : "cpu-sampling" , providers : "Foo:0x1:4" ) ,
195+ new CollectArgs ( profile : "cpu-sampling" , providers : "Foo:0x1:4" ) ,
171196 ExpectProviders (
172- "profileAndProviders" ,
173197 FormatProvider ( "Foo" , "0000000000000001" , "Informational" , 4 , "--providers" ) ,
174198 FormatProvider ( "Microsoft-DotNETCore-SampleProfiler" , "0000F00000000000" , "Informational" , 4 , "--profile" ) ,
175199 FormatProvider ( "Microsoft-Windows-DotNETRuntime" , "00000014C14FCCBD" , "Informational" , 4 , "--profile" ) )
176200 } ;
177201
178202 yield return new object [ ]
179203 {
180- new CollectArgs ( output : new FileInfo ( "profileAndClrEventsIgnored" ) , profile : "cpu-sampling" , clrevents : "gc" ) ,
204+ new CollectArgs ( profile : "cpu-sampling" , clrevents : "gc" ) ,
181205 ExpectProvidersWithMessages (
182- "profileAndClrEventsIgnored" ,
183206 new [ ]
184207 {
185208 "The argument --clrevents gc will be ignored because the CLR provider was configured via either --profile or --providers command."
@@ -190,18 +213,16 @@ public static IEnumerable<object[]> BasicCases()
190213
191214 yield return new object [ ]
192215 {
193- new CollectArgs ( output : new FileInfo ( "profileOverriddenRuntime" ) , profile : "cpu-sampling" , providers : "Microsoft-Windows-DotNETRuntime:0x1:4" ) ,
216+ new CollectArgs ( profile : "cpu-sampling" , providers : "Microsoft-Windows-DotNETRuntime:0x1:4" ) ,
194217 ExpectProviders (
195- "profileOverriddenRuntime" ,
196218 FormatProvider ( "Microsoft-Windows-DotNETRuntime" , "0000000000000001" , "Informational" , 4 , "--providers" ) ,
197219 FormatProvider ( "Microsoft-DotNETCore-SampleProfiler" , "0000F00000000000" , "Informational" , 4 , "--profile" ) )
198220 } ;
199221
200222 yield return new object [ ]
201223 {
202- new CollectArgs ( output : new FileInfo ( "providersClrEventsIgnored" ) , providers : "Microsoft-Windows-DotNETRuntime:0x1:4" , clrevents : "gc" ) ,
224+ new CollectArgs ( providers : "Microsoft-Windows-DotNETRuntime:0x1:4" , clrevents : "gc" ) ,
203225 ExpectProvidersWithMessages (
204- "providersClrEventsIgnored" ,
205226 new [ ]
206227 {
207228 "The argument --clrevents gc will be ignored because the CLR provider was configured via either --profile or --providers command."
@@ -211,38 +232,34 @@ public static IEnumerable<object[]> BasicCases()
211232
212233 yield return new object [ ]
213234 {
214- new CollectArgs ( output : new FileInfo ( "clrEventsOnly" ) , clrevents : "gc+jit" ) ,
235+ new CollectArgs ( clrevents : "gc+jit" ) ,
215236 ExpectProviders (
216- "clrEventsOnly" ,
217237 FormatProvider ( "Microsoft-Windows-DotNETRuntime" , "0000000000000011" , "Informational" , 4 , "--clrevents" ) )
218238 } ;
219239
220240 yield return new object [ ]
221241 {
222- new CollectArgs ( output : new FileInfo ( "clrEventsVerbose" ) , clrevents : "gc+jit" , clreventlevel : "5" ) ,
242+ new CollectArgs ( clrevents : "gc+jit" , clreventlevel : "5" ) ,
223243 ExpectProviders (
224- "clrEventsVerbose" ,
225244 FormatProvider ( "Microsoft-Windows-DotNETRuntime" , "0000000000000011" , "Verbose" , 5 , "--clrevents" ) )
226245 } ;
227246 }
228247
229- private const string ProcessPlaceHolder = "Process : <PROCESS>" ;
230- private static string outputPrefix = $ "Output File : { Directory . GetCurrentDirectory ( ) + Path . DirectorySeparatorChar } ";
248+ private static string outputFile = $ "Output File : { Directory . GetCurrentDirectory ( ) + Path . DirectorySeparatorChar } trace.nettrace";
231249 private const string ProviderHeader = "Provider Name Keywords Level Enabled By" ;
232250 private static readonly string [ ] CommonTail = [
233- "" ,
234- "Recording trace in progress. Press <Enter> or <Ctrl+C> to exit..." ,
251+ "Process : <PROCESS>" ,
252+ outputFile ,
253+ "[dd:hh:mm:ss]\t Recording trace 38.00 (B)" ,
254+ "Press <Enter> or <Ctrl+C> to exit..." ,
235255 "\n Trace completed."
236256 ] ;
237257
238- private static string [ ] Expect ( string outputFile , params string [ ] lines )
239- => [ .. lines , ProcessPlaceHolder , outputPrefix + outputFile , .. CommonTail ] ;
240-
241- private static string [ ] ExpectProviders ( string outputFile , params string [ ] providerLines )
242- => Expect ( outputFile , [ "" , ProviderHeader , .. providerLines , "" ] ) ;
258+ private static string [ ] ExpectProviders ( params string [ ] providerLines )
259+ => ExpectProvidersWithMessages ( new string [ 0 ] , providerLines ) ;
243260
244- private static string [ ] ExpectProvidersWithMessages ( string outputFile , string [ ] messages , params string [ ] providerLines )
245- => Expect ( outputFile , [ .. messages , "" , ProviderHeader , .. providerLines , "" ] ) ;
261+ private static string [ ] ExpectProvidersWithMessages ( string [ ] messages , params string [ ] providerLines )
262+ => [ .. messages , "" , ProviderHeader , .. providerLines , "" , .. CommonTail ] ;
246263
247264 private static string FormatProvider ( string name , string keywordsHex , string levelName , int levelValue , string enabledBy )
248265 {
0 commit comments