11// Copyright (c) Microsoft. All rights reserved.
22// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33
4+ using System ;
45using System . Collections . Generic ;
56using System . IO ;
67using System . Linq ;
@@ -34,6 +35,8 @@ public class SbomAggregationWorkflowTests
3435 private const string PathToSpdx22ManifestForArtifactKey2 = ExternalManifestDir2 + RelativePathToSpdx22Manifest ;
3536 private const string PathToSpdx30ManifestForArtifactKey2 = ExternalManifestDir2 + RelativePathToSpdx30Manifest ;
3637 private const string TempDirPath = "temp-dir" ;
38+ private const string PackageId1 = "package-id-1" ;
39+ private const string PackageId2 = "package-id-2" ;
3740
3841 private Mock < ILogger > loggerMock ;
3942 private Mock < IRecorder > recorderMock ;
@@ -50,6 +53,8 @@ public class SbomAggregationWorkflowTests
5053 private Mock < IMetadataBuilderFactory > metadataBuilderFactoryMock ;
5154 private SbomAggregationWorkflow testSubject ;
5255
56+ private List < SbomPackage > actualPackageList ;
57+
5358 private Dictionary < string , ArtifactInfo > artifactInfoMapStub = new Dictionary < string , ArtifactInfo > ( )
5459 {
5560 { ArtifactKey1 , new ArtifactInfo ( ) { IgnoreMissingFiles = true , SkipSigningCheck = true } } ,
@@ -92,6 +97,8 @@ public void BeforeEachTest()
9297 fileSystemUtilsMock . Object ,
9398 metadataBuilderFactoryMock . Object ,
9499 new [ ] { mergeableContent22ProviderMock . Object , mergeableContent30ProviderMock . Object } ) ;
100+
101+ actualPackageList = null ;
95102 }
96103
97104 [ TestCleanup ]
@@ -118,7 +125,9 @@ public async Task RunAsync_ReturnsFalseOnNoArtifactInfoMapInput()
118125 . Returns ( new ConfigurationSetting < Dictionary < string , ArtifactInfo > > ( new Dictionary < string , ArtifactInfo > ( ) ) ) ;
119126
120127 var result = await testSubject . RunAsync ( ) ;
128+
121129 Assert . IsFalse ( result ) ;
130+ Assert . IsNull ( actualPackageList ) ;
122131 }
123132
124133 [ TestMethod ]
@@ -144,7 +153,9 @@ public async Task RunAsync_ReturnsFalseOnNoValidSpdxSbomsFound()
144153 }
145154
146155 var result = await testSubject . RunAsync ( ) ;
156+
147157 Assert . IsFalse ( result ) ;
158+ Assert . IsNull ( actualPackageList ) ;
148159 }
149160
150161 [ TestMethod ]
@@ -182,16 +193,21 @@ public async Task RunAsync_ReturnsFalseOnOnlySpdx30SbomsFound()
182193 }
183194
184195 var result = await testSubject . RunAsync ( ) ;
196+
185197 Assert . IsFalse ( result ) ;
198+ Assert . IsNull ( actualPackageList ) ;
186199 }
187200
188201 [ TestMethod ]
189202 public async Task RunAsync_ReturnsFalseOnFailedValidationWorkflow ( )
190203 {
191204 SetUpSbomsToValidate ( ) ;
192205 SetUpMinimalValidation ( false ) ;
206+
193207 var result = await testSubject . RunAsync ( ) ;
208+
194209 Assert . IsFalse ( result ) ;
210+ Assert . IsNull ( actualPackageList ) ;
195211 }
196212
197213 [ TestMethod ]
@@ -212,7 +228,9 @@ public async Task RunAsync_MixOfValidAndInvalidInputSboms()
212228 sbomValidationWorkflowMock1 . Setup ( x => x . RunAsync ( ) ) . ReturnsAsync ( false ) ;
213229
214230 var result = await testSubject . RunAsync ( ) ;
231+
215232 Assert . IsFalse ( result ) ;
233+ Assert . IsNull ( actualPackageList ) ;
216234 }
217235
218236 [ TestMethod ]
@@ -226,29 +244,70 @@ public async Task RunAsync_MinimalHappyPath_CallsGenerationWorkflow(bool expecte
226244 SetupMinimalMergeableContentProviderMocks ( ) ;
227245
228246 var result = await testSubject . RunAsync ( ) ;
247+
229248 Assert . AreEqual ( expectedResult , result ) ;
249+ ValidateActualPackageList ( ) ;
230250 }
231251
232252 private void SetupMinimalMergeableContentProviderMocks ( )
233253 {
234- var minimalMergeableContent = new MergeableContent (
235- new List < SbomPackage > { new SbomPackage ( ) } , Enumerable . Empty < SbomRelationship > ( ) ) ;
254+ // mergeableContent 1 has the root package that depends on PackageId1.
255+ // mergeableContent 2 has the root package that depends on PackageId2, which in turn depends on PackageId1.
256+ var minimalMergeableContent1 = new MergeableContent (
257+ [
258+ new SbomPackage { Id = PackageId1 }
259+ ] ,
260+ Enumerable . Empty < SbomRelationship > ( ) ) ;
261+ var minimalMergeableContent2 = new MergeableContent (
262+ [
263+ new SbomPackage { Id = PackageId1 } ,
264+ new SbomPackage { Id = PackageId2 }
265+ ] ,
266+ [
267+ new SbomRelationship
268+ {
269+ SourceElementId = PackageId2 ,
270+ TargetElementId = PackageId1 ,
271+ RelationshipType = "DEPENDS_ON"
272+ }
273+ ] ) ;
274+
275+ MergeableContent nullMergeableContent = null ;
236276
237277 mergeableContent22ProviderMock
238- . Setup ( m => m . TryGetContent ( PathToSpdx22ManifestForArtifactKey1 , out minimalMergeableContent ) )
278+ . Setup ( m => m . TryGetContent ( PathToSpdx22ManifestForArtifactKey1 , out minimalMergeableContent1 ) )
239279 . Returns ( true ) ;
240280 mergeableContent22ProviderMock
241- . Setup ( m => m . TryGetContent ( PathToSpdx22ManifestForArtifactKey2 , out minimalMergeableContent ) )
281+ . Setup ( m => m . TryGetContent ( PathToSpdx22ManifestForArtifactKey2 , out minimalMergeableContent2 ) )
242282 . Returns ( true ) ;
243283 mergeableContent30ProviderMock
244- . Setup ( m => m . TryGetContent ( PathToSpdx30ManifestForArtifactKey1 , out minimalMergeableContent ) )
245- . Returns ( true ) ;
284+ . Setup ( m => m . TryGetContent ( PathToSpdx30ManifestForArtifactKey1 , out nullMergeableContent ) )
285+ . Returns ( false ) ;
246286 mergeableContent30ProviderMock
247- . Setup ( m => m . TryGetContent ( PathToSpdx30ManifestForArtifactKey2 , out minimalMergeableContent ) )
248- . Returns ( true ) ;
287+ . Setup ( m => m . TryGetContent ( PathToSpdx30ManifestForArtifactKey2 , out nullMergeableContent ) )
288+ . Returns ( false ) ;
289+
290+ recorderMock . Setup ( m => m . RecordAggregationSource ( It . IsAny < string > ( ) , 1 , 0 ) ) ; // minimalMergeableContent1
291+ recorderMock . Setup ( m => m . RecordAggregationSource ( It . IsAny < string > ( ) , 2 , 1 ) ) ; // minimalMergeableContent2
292+ }
293+
294+ private void ValidateActualPackageList ( )
295+ {
296+ Assert . IsNotNull ( actualPackageList ) ;
297+ Assert . AreEqual ( 2 , actualPackageList . Count ) ;
298+
299+ // Package order is not determined, so sort it to simplify our assertions.
300+ actualPackageList . Sort ( ( x , y ) => string . Compare ( x . Id , y . Id , StringComparison . Ordinal ) ) ;
301+
302+ // PackageId1 should list PackageId2 in DependOn
303+ Assert . AreEqual ( PackageId1 , actualPackageList [ 0 ] . Id ) ;
304+ Assert . IsNotNull ( actualPackageList [ 0 ] . DependOn ) ;
305+ Assert . AreEqual ( 1 , actualPackageList [ 0 ] . DependOn . Count ) ;
306+ Assert . AreEqual ( PackageId2 , actualPackageList [ 0 ] . DependOn [ 0 ] ) ;
249307
250- recorderMock . Setup ( m => m . RecordAggregationSource (
251- It . IsAny < string > ( ) , 1 /* package count */ , 0 /* relationship count */ ) ) ;
308+ // PackageId2 should have a null DependOn
309+ Assert . AreEqual ( PackageId2 , actualPackageList [ 1 ] . Id ) ;
310+ Assert . IsNull ( actualPackageList [ 1 ] . DependOn ) ;
252311 }
253312
254313 private void SetUpSbomsToValidate ( )
@@ -328,7 +387,8 @@ private void SetupMinimalGenerationMocks(bool expectedResult)
328387 configurationMock . SetupSet ( m => m . BuildComponentPath = It . IsAny < ConfigurationSetting < string > > ( ) ) ;
329388 configurationMock . SetupSet ( m => m . BuildDropPath = It . IsAny < ConfigurationSetting < string > > ( ) ) ;
330389 configurationMock . SetupSet ( m => m . ManifestInfo = It . IsAny < ConfigurationSetting < IList < ManifestInfo > > > ( ) ) ;
331- configurationMock . SetupSet ( m => m . PackagesList = It . IsAny < ConfigurationSetting < IEnumerable < SbomPackage > > > ( ) ) ;
390+ configurationMock . SetupSet ( m => m . PackagesList = It . IsAny < ConfigurationSetting < IEnumerable < SbomPackage > > > ( ) )
391+ . Callback < ConfigurationSetting < IEnumerable < SbomPackage > > > ( c => actualPackageList = c . Value . ToList ( ) ) ;
332392
333393 fileSystemUtilsMock . Setup ( m => m . CreateDirectory ( Path . Join ( TempDirPath , "aggregated-build-drop" ) ) ) . Returns < DirectoryInfo > ( null ) ;
334394
0 commit comments