2019-10-10 00:52:42 -04:00
using GitHub.Runner.Listener ;
2021-01-14 13:26:07 -05:00
using GitHub.Runner.Listener.Check ;
2019-10-10 00:52:42 -04:00
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")]
2019-12-09 17:54:41 -05:00
[Trait("Category", "Runner")]
public void RunnerInterfacesSpecifyDefaultImplementation ( )
2019-10-10 00:52:42 -04:00
{
// Validate all interfaces in the Listener assembly define a valid service locator attribute.
// Otherwise, the interface needs to whitelisted.
var whitelist = new [ ]
{
2021-01-14 13:26:07 -05:00
typeof ( ICredentialProvider ) ,
typeof ( ICheckExtension ) ,
2019-10-10 00:52:42 -04:00
} ;
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 ) ,
2020-08-28 15:32:25 -04:00
typeof ( IFileCommandExtension ) ,
2019-10-10 00:52:42 -04:00
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 ;
}
2021-01-14 13:26:07 -05:00
if ( interfaceTypeInfo . FullName . Contains ( "IConverter" ) )
{
2019-10-10 00:52:42 -04:00
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 ) ;
}
}
}
}