@@ -14,7 +14,9 @@ namespace VirtualClient
1414 using Moq ;
1515 using NUnit . Framework ;
1616 using VirtualClient . Common ;
17+ using VirtualClient . Common . Contracts ;
1718 using VirtualClient . Common . Telemetry ;
19+ using VirtualClient . Contracts ;
1820
1921 [ TestFixture ]
2022 [ Category ( "Unit" ) ]
@@ -551,5 +553,131 @@ public async Task LogProcessDetailsExtensionLogsToTheExpectedStandardErrorToFile
551553 Assert . IsTrue ( standardErrorConfirmed , "Standard error not confirmed." ) ;
552554 }
553555 }
556+
557+ [ Test ]
558+ public async Task LogProcessDetailsExtensionUploadsLogFilesByDefaultWhenAContentStoreIsProvided ( )
559+ {
560+ bool confirmed = false ;
561+ Mock < IProcessProxy > mockProcess = new Mock < IProcessProxy > ( ) . Setup ( ) ;
562+
563+ using ( TestExecutor component = new TestExecutor ( this ) )
564+ {
565+ this . FileSystem
566+ . Setup ( fs => fs . File . WriteAllTextAsync ( It . IsAny < string > ( ) , It . IsAny < string > ( ) , It . IsAny < CancellationToken > ( ) ) )
567+ . Callback < string , string , CancellationToken > ( ( path , content , token ) =>
568+ {
569+ if ( path . StartsWith ( this . PlatformSpecifics . ContentUploadsDirectory ) )
570+ {
571+ confirmed = true ;
572+ FileUploadDescriptor descriptor = content . FromJson < FileUploadDescriptor > ( ) ;
573+ Assert . IsNotNull ( descriptor ) ;
574+ }
575+ } )
576+ . Returns ( Task . CompletedTask ) ;
577+
578+ await component . LogProcessDetailsAsync ( mockProcess . Object , EventContext . None , logToTelemetry : false , logToFile : true ) ;
579+ Assert . IsTrue ( confirmed ) ;
580+ }
581+ }
582+
583+ [ Test ]
584+ public async Task LogProcessDetailsExtensionSupportsDeferringLogFileUploads ( )
585+ {
586+ bool deferred = true ;
587+ Mock < IProcessProxy > mockProcess = new Mock < IProcessProxy > ( ) . Setup ( ) ;
588+
589+ using ( TestExecutor component = new TestExecutor ( this ) )
590+ {
591+ component . Parameters [ nameof ( component . DeferUpload ) ] = true ;
592+
593+ this . FileSystem
594+ . Setup ( fs => fs . File . WriteAllTextAsync ( It . IsAny < string > ( ) , It . IsAny < string > ( ) , It . IsAny < CancellationToken > ( ) ) )
595+ . Callback < string , string , CancellationToken > ( ( path , content , token ) =>
596+ {
597+ if ( path . StartsWith ( this . PlatformSpecifics . ContentUploadsDirectory ) )
598+ {
599+ deferred = false ;
600+ }
601+ } )
602+ . Returns ( Task . CompletedTask ) ;
603+
604+ await component . LogProcessDetailsAsync ( mockProcess . Object , EventContext . None , logToTelemetry : false , logToFile : true ) ;
605+ Assert . IsTrue ( deferred ) ;
606+ }
607+ }
608+
609+ [ Test ]
610+ public async Task LogProcessDetailsExtensionDeletesLogFilesOnUploadsOnlyWhenExpected ( )
611+ {
612+ bool confirmed = false ;
613+ bool shouldBeDeleted = false ;
614+ Mock < IProcessProxy > mockProcess = new Mock < IProcessProxy > ( ) . Setup ( ) ;
615+
616+ using ( TestExecutor component = new TestExecutor ( this ) )
617+ {
618+ // By default, log files should NOT be deleted on upload.
619+ this . FileSystem
620+ . Setup ( fs => fs . File . WriteAllTextAsync ( It . IsAny < string > ( ) , It . IsAny < string > ( ) , It . IsAny < CancellationToken > ( ) ) )
621+ . Callback < string , string , CancellationToken > ( ( path , content , token ) =>
622+ {
623+ if ( path . StartsWith ( this . PlatformSpecifics . ContentUploadsDirectory ) )
624+ {
625+ confirmed = true ;
626+ FileUploadDescriptor descriptor = content . FromJson < FileUploadDescriptor > ( ) ;
627+ Assert . IsNotNull ( descriptor ) ;
628+ Assert . AreEqual ( shouldBeDeleted , descriptor . DeleteOnUpload , "Log file delete does not match expectation." ) ;
629+ }
630+ } )
631+ . Returns ( Task . CompletedTask ) ;
632+
633+ await component . LogProcessDetailsAsync ( mockProcess . Object , EventContext . None , logToTelemetry : false , logToFile : true ) ;
634+ Assert . IsTrue ( confirmed ) ;
635+
636+ // If requested, however, log files should be deleted on upload.
637+ confirmed = false ;
638+ shouldBeDeleted = true ;
639+ component . Parameters [ nameof ( component . DeleteOnUpload ) ] = true ;
640+
641+ await component . LogProcessDetailsAsync ( mockProcess . Object , EventContext . None , logToTelemetry : false , logToFile : true ) ;
642+ Assert . IsTrue ( confirmed ) ;
643+ }
644+ }
645+
646+ [ Test ]
647+ public async Task LogProcessDetailsExtensionIncludesAManifestWithLogFilesOnUploadsOnlyWhenExpected ( )
648+ {
649+ bool confirmed = false ;
650+ bool shouldBeIncluded = false ;
651+ Mock < IProcessProxy > mockProcess = new Mock < IProcessProxy > ( ) . Setup ( ) ;
652+
653+ using ( TestExecutor component = new TestExecutor ( this ) )
654+ {
655+ // By default, a manifest should NOT be included with log file uploads.
656+ this . FileSystem
657+ . Setup ( fs => fs . File . WriteAllTextAsync ( It . IsAny < string > ( ) , It . IsAny < string > ( ) , It . IsAny < CancellationToken > ( ) ) )
658+ . Callback < string , string , CancellationToken > ( ( path , content , token ) =>
659+ {
660+ if ( path . StartsWith ( this . PlatformSpecifics . ContentUploadsDirectory ) )
661+ {
662+ confirmed = true ;
663+ FileUploadDescriptor descriptor = content . FromJson < FileUploadDescriptor > ( ) ;
664+ Assert . IsNotNull ( descriptor ) ;
665+ Assert . AreEqual ( shouldBeIncluded , descriptor . IncludeManifest , "Manifest inclusion does not match expectation." ) ;
666+ }
667+ } )
668+ . Returns ( Task . CompletedTask ) ;
669+
670+ await component . LogProcessDetailsAsync ( mockProcess . Object , EventContext . None , logToTelemetry : false , logToFile : true ) ;
671+ Assert . IsTrue ( confirmed ) ;
672+
673+ // If requested, however, log files should be deleted on upload.
674+ confirmed = false ;
675+ shouldBeIncluded = true ;
676+ component . Parameters [ nameof ( component . IncludeManifestOnUpload ) ] = true ;
677+
678+ await component . LogProcessDetailsAsync ( mockProcess . Object , EventContext . None , logToTelemetry : false , logToFile : true ) ;
679+ Assert . IsTrue ( confirmed ) ;
680+ }
681+ }
554682 }
555683}
0 commit comments