Skip to content

Commit 8ed990c

Browse files
authored
adding test to flag any changing dependencies for review (v2) (#6677)
1 parent 61ace95 commit 8ed990c

File tree

3 files changed

+8661
-1
lines changed

3 files changed

+8661
-1
lines changed
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Diagnostics.CodeAnalysis;
7+
using System.IO;
8+
using System.Linq;
9+
using System.Text;
10+
using Microsoft.Azure.WebJobs.Script.Description;
11+
using Microsoft.Extensions.DependencyModel;
12+
using Xunit;
13+
14+
namespace Microsoft.Azure.WebJobs.Script.Tests
15+
{
16+
public class DependencyTests
17+
{
18+
// These are changed often and controlled by us, so we don't need to fail if they are updated.
19+
private static readonly string[] _excludedList = new[]
20+
{
21+
"Microsoft.Azure.WebJobs.Script.WebHost.dll",
22+
"Microsoft.Azure.WebJobs.dll",
23+
"Microsoft.Azure.WebJobs.Host.dll",
24+
"Microsoft.Azure.WebJobs.Logging.ApplicationInsights.dll",
25+
"Microsoft.Azure.WebJobs.Script.Abstractions.dll",
26+
"Microsoft.Azure.WebJobs.Extensions.dll",
27+
"Microsoft.Azure.WebJobs.Extensions.Http.dll",
28+
"Microsoft.Azure.WebJobs.Host.Storage.dll",
29+
"Microsoft.Azure.WebJobs.Logging.dll"
30+
};
31+
32+
private readonly DependencyContextJsonReader _reader = new DependencyContextJsonReader();
33+
private readonly IEnumerable<string> _rids = DependencyHelper.GetRuntimeFallbacks();
34+
35+
[Fact]
36+
public void Verify_DepsJsonChanges()
37+
{
38+
string depsJsonFileName = "Microsoft.Azure.WebJobs.Script.WebHost.deps.json";
39+
40+
string oldDepsJson = Path.GetFullPath(depsJsonFileName);
41+
var newDepsJson = Directory.GetFiles(Path.GetFullPath(@"..\..\..\..\..\src\WebJobs.Script.WebHost\bin\"), depsJsonFileName, SearchOption.AllDirectories).FirstOrDefault();
42+
43+
Assert.True(File.Exists(oldDepsJson), $"{oldDepsJson} not found.");
44+
Assert.True(File.Exists(newDepsJson), $"{newDepsJson} not found.");
45+
46+
IEnumerable<RuntimeFile> oldAssets = GetRuntimeFiles(oldDepsJson);
47+
IEnumerable<RuntimeFile> newAssets = GetRuntimeFiles(newDepsJson);
48+
49+
var comparer = new RuntimeFileComparer();
50+
51+
var removed = oldAssets.Except(newAssets, comparer).ToList();
52+
var added = newAssets.Except(oldAssets, comparer).ToList();
53+
54+
bool succeed = removed.Count == 0 && added.Count == 0;
55+
56+
if (succeed)
57+
{
58+
return;
59+
}
60+
61+
IList<RuntimeFile> changed = new List<RuntimeFile>();
62+
StringBuilder sb = new StringBuilder();
63+
sb.AppendLine("The dependencies in WebHost have changed and should be reviewed before proceeding. Follow up with brettsam or fabiocav for next steps.");
64+
sb.AppendLine();
65+
sb.AppendLine($"Previous file: {oldDepsJson}");
66+
sb.AppendLine($"New file: {newDepsJson}");
67+
sb.AppendLine();
68+
sb.AppendLine(" Changed:");
69+
foreach (RuntimeFile oldFile in oldAssets)
70+
{
71+
string fileName = Path.GetFileName(oldFile.Path);
72+
if (_excludedList.Contains(fileName))
73+
{
74+
continue;
75+
}
76+
77+
RuntimeFile newFile = newAssets.SingleOrDefault(p =>
78+
{
79+
return Path.GetFileName(p.Path) == fileName &&
80+
p.FileVersion != oldFile.FileVersion &&
81+
p.AssemblyVersion != oldFile.AssemblyVersion;
82+
});
83+
84+
if (newFile != null)
85+
{
86+
sb.AppendLine($" - {fileName}: {oldFile.AssemblyVersion}/{oldFile.FileVersion} -> {newFile.AssemblyVersion}/{newFile.FileVersion}");
87+
changed.Add(oldFile);
88+
changed.Add(newFile);
89+
}
90+
}
91+
92+
sb.AppendLine();
93+
sb.AppendLine(" Removed:");
94+
foreach (RuntimeFile f in removed.Except(changed))
95+
{
96+
sb.AppendLine($" - {Path.GetFileName(f.Path)}: {f.AssemblyVersion}/{f.FileVersion}");
97+
}
98+
sb.AppendLine();
99+
sb.AppendLine(" Added:");
100+
foreach (RuntimeFile f in added.Except(changed))
101+
{
102+
sb.AppendLine($" - {Path.GetFileName(f.Path)}: {f.AssemblyVersion}/{f.FileVersion}");
103+
}
104+
105+
Assert.True(succeed, sb.ToString());
106+
}
107+
108+
private IEnumerable<RuntimeFile> GetRuntimeFiles(string depsJsonFileName)
109+
{
110+
using (Stream s = new FileStream(depsJsonFileName, FileMode.Open))
111+
{
112+
DependencyContext deps = _reader.Read(s);
113+
114+
return deps.RuntimeLibraries
115+
.SelectMany(l => SelectRuntimeAssemblyGroup(_rids, l.RuntimeAssemblyGroups))
116+
.Where(l => !_excludedList.Contains(Path.GetFileName(l.Path)))
117+
.OrderBy(p => Path.GetFileName(p.Path));
118+
}
119+
}
120+
121+
private static IEnumerable<RuntimeFile> SelectRuntimeAssemblyGroup(IEnumerable<string> rids, IReadOnlyList<RuntimeAssetGroup> runtimeAssemblyGroups)
122+
{
123+
// Attempt to load group for the current RID graph
124+
foreach (var rid in rids)
125+
{
126+
var assemblyGroup = runtimeAssemblyGroups.FirstOrDefault(g => string.Equals(g.Runtime, rid, StringComparison.OrdinalIgnoreCase));
127+
if (assemblyGroup != null)
128+
{
129+
return assemblyGroup.RuntimeFiles;
130+
}
131+
}
132+
133+
// If unsuccessful, load default assets, making sure the path is flattened to reflect deployed files
134+
return runtimeAssemblyGroups.GetDefaultRuntimeFileAssets();
135+
}
136+
137+
private class RuntimeFileComparer : IEqualityComparer<RuntimeFile>
138+
{
139+
public bool Equals(RuntimeFile x, RuntimeFile y)
140+
{
141+
return x.AssemblyVersion == y.AssemblyVersion &&
142+
x.FileVersion == y.FileVersion &&
143+
x.Path == y.Path;
144+
}
145+
146+
public int GetHashCode(RuntimeFile obj)
147+
{
148+
string code = obj.Path + obj.AssemblyVersion + obj.FileVersion;
149+
return code.GetHashCode();
150+
}
151+
}
152+
}
153+
}

0 commit comments

Comments
 (0)