Files
runner/src/Test/L0/ServiceInterfacesL0.cs
Thomas Boop 9976cb92a0 Add Runner File Commands (#684)
* Add File Runner Commands
2020-08-28 15:32:25 -04:00

115 lines
5.0 KiB
C#

using GitHub.Runner.Listener;
using GitHub.Runner.Listener.Configuration;
using GitHub.Runner.Worker;
using GitHub.Runner.Worker.Handlers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Xunit;
namespace GitHub.Runner.Common.Tests
{
public sealed class ServiceInterfacesL0
{
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Runner")]
public void RunnerInterfacesSpecifyDefaultImplementation()
{
// Validate all interfaces in the Listener assembly define a valid service locator attribute.
// Otherwise, the interface needs to whitelisted.
var whitelist = new[]
{
typeof(ICredentialProvider)
};
Validate(
assembly: typeof(IMessageListener).GetTypeInfo().Assembly,
whitelist: whitelist);
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Common")]
public void CommonInterfacesSpecifyDefaultImplementation()
{
// Validate all interfaces in the Common assembly define a valid service locator attribute.
// Otherwise, the interface needs to whitelisted.
var whitelist = new[]
{
typeof(IRunnerService),
typeof(ICredentialProvider),
typeof(IExtension),
typeof(IHostContext),
typeof(ITraceManager),
typeof(IThrottlingReporter),
};
Validate(
assembly: typeof(IHostContext).GetTypeInfo().Assembly,
whitelist: whitelist);
}
[Fact]
[Trait("Level", "L0")]
[Trait("Category", "Worker")]
public void WorkerInterfacesSpecifyDefaultImplementation()
{
// Validate all interfaces in the Worker assembly define a valid service locator attribute.
// Otherwise, the interface needs to whitelisted.
var whitelist = new[]
{
typeof(IActionCommandExtension),
typeof(IExecutionContext),
typeof(IFileCommandExtension),
typeof(IHandler),
typeof(IJobExtension),
typeof(IStep),
typeof(IStepHost),
typeof(IDiagnosticLogManager),
typeof(IEnvironmentContextData)
};
Validate(
assembly: typeof(IStepsRunner).GetTypeInfo().Assembly,
whitelist: whitelist);
}
private static void Validate(Assembly assembly, params Type[] whitelist)
{
// Iterate over all non-whitelisted interfaces contained within the assembly.
IDictionary<TypeInfo, Type> w = whitelist.ToDictionary(x => x.GetTypeInfo());
foreach (TypeInfo interfaceTypeInfo in assembly.DefinedTypes.Where(x => x.IsInterface && !w.ContainsKey(x)))
{
// Temporary hack due to shared code copied in two places.
if (interfaceTypeInfo.FullName.StartsWith("GitHub.DistributedTask"))
{
continue;
}
if (interfaceTypeInfo.FullName.Contains("IConverter")){
continue;
}
// Assert the ServiceLocatorAttribute is defined on the interface.
CustomAttributeData attribute =
interfaceTypeInfo
.CustomAttributes
.SingleOrDefault(x => x.AttributeType == typeof(ServiceLocatorAttribute));
Assert.True(attribute != null, $"Missing {nameof(ServiceLocatorAttribute)} for interface '{interfaceTypeInfo.FullName}'. Add the attribute to the interface or whitelist the interface in the test.");
// Assert the interface is mapped to a concrete type.
CustomAttributeNamedArgument defaultArg =
attribute
.NamedArguments
.SingleOrDefault(x => String.Equals(x.MemberName, ServiceLocatorAttribute.DefaultPropertyName, StringComparison.Ordinal));
Type concreteType = defaultArg.TypedValue.Value as Type;
string invalidConcreteTypeMessage = $"Invalid Default parameter on {nameof(ServiceLocatorAttribute)} for the interface '{interfaceTypeInfo.FullName}'. The default implementation must not be null, must not be an interface, must be a class, and must implement the interface '{interfaceTypeInfo.FullName}'.";
Assert.True(concreteType != null, invalidConcreteTypeMessage);
TypeInfo concreteTypeInfo = concreteType.GetTypeInfo();
Assert.False(concreteTypeInfo.IsInterface, invalidConcreteTypeMessage);
Assert.True(concreteTypeInfo.IsClass, invalidConcreteTypeMessage);
Assert.True(concreteTypeInfo.ImplementedInterfaces.Any(x => x.GetTypeInfo() == interfaceTypeInfo), invalidConcreteTypeMessage);
}
}
}
}