diff --git a/src/ApiService/.editorconfig b/src/ApiService/.editorconfig index 66fb2e462..a8284cde1 100644 --- a/src/ApiService/.editorconfig +++ b/src/ApiService/.editorconfig @@ -139,3 +139,26 @@ csharp_preserve_single_line_blocks = true [*.{cs}] dotnet_diagnostic.IDE0005.severity = warning + +# allow use of FirstOrDefault/LastOrDefault: https://github.com/dotnet/roslyn-analyzers/issues/1817 & https://github.com/dotnet/roslyn-analyzers/pull/4211#issuecomment-1003578755 +dotnet_code_quality.CA1826.exclude_ordefault_methods = true + +# permit underscores in identifier names (e.g. tests, constants) +dotnet_diagnostic.CA1707.severity = none + +# don't care about names that conflict with keywords in other languages +dotnet_diagnostic.CA1716.severity = none + +# don't care about names that contain built-in identifiers +dotnet_diagnostic.CA1711.severity = none +dotnet_diagnostic.CA1720.severity = none + +# allow static fields on generic types +dotnet_diagnostic.CA1000.severity = none + +# don't worry about performance of ILogger invocations (yet?) +dotnet_diagnostic.CA1848.severity = none + +# allow throwing base "Exception" class, since it's done a lot +# TODO: improve this +dotnet_diagnostic.CA2201.severity = suggestion diff --git a/src/ApiService/ApiService/Log.cs b/src/ApiService/ApiService/Log.cs index 7ab3288b0..7a953f905 100644 --- a/src/ApiService/ApiService/Log.cs +++ b/src/ApiService/ApiService/Log.cs @@ -59,7 +59,7 @@ class AppInsights : ILog { //TODO: Should we write errors and Exception to std err ? class Console : ILog { - private string DictToString(IReadOnlyDictionary? d) { + private static string DictToString(IReadOnlyDictionary? d) { if (d is null) { return string.Empty; } else { @@ -67,14 +67,14 @@ class Console : ILog { } } - private void LogTags(Guid correlationId, IReadOnlyDictionary tags) { + private static void LogTags(Guid correlationId, IReadOnlyDictionary tags) { var ts = DictToString(tags); if (!string.IsNullOrEmpty(ts)) { System.Console.WriteLine($"[{correlationId}] Tags:{ts}"); } } - private void LogMetrics(Guid correlationId, IReadOnlyDictionary? metrics) { + private static void LogMetrics(Guid correlationId, IReadOnlyDictionary? metrics) { var ms = DictToString(metrics); if (!string.IsNullOrEmpty(ms)) { System.Console.Out.WriteLine($"[{correlationId}] Metrics:{DictToString(metrics)}"); @@ -126,7 +126,7 @@ internal interface ILogTracerInternal : ILogTracer { public class LogTracer : ILogTracerInternal { - private string? GetCaller() { + private static string? GetCaller() { return new StackTrace()?.GetFrame(2)?.GetMethod()?.DeclaringType?.FullName; } diff --git a/src/ApiService/ApiService/OneFuzzTypes/Enums.cs b/src/ApiService/ApiService/OneFuzzTypes/Enums.cs index f6fe57237..c21a19905 100644 --- a/src/ApiService/ApiService/OneFuzzTypes/Enums.cs +++ b/src/ApiService/ApiService/OneFuzzTypes/Enums.cs @@ -8,7 +8,7 @@ public enum ErrorCode { INVALID_PERMISSION = 451, MISSING_EULA_AGREEMENT = 452, INVALID_JOB = 453, - INVALID_TASK = 453, + INVALID_TASK = INVALID_JOB, UNABLE_TO_ADD_TASK_TO_JOB = 454, INVALID_CONTAINER = 455, UNABLE_TO_RESIZE = 456, diff --git a/src/ApiService/ApiService/OneFuzzTypes/Model.cs b/src/ApiService/ApiService/OneFuzzTypes/Model.cs index ae866b878..b78d1539b 100644 --- a/src/ApiService/ApiService/OneFuzzTypes/Model.cs +++ b/src/ApiService/ApiService/OneFuzzTypes/Model.cs @@ -333,7 +333,7 @@ public record InstanceConfig "Standard_B2s") { } public InstanceConfig() : this(String.Empty) { } - public List? CheckAdmins(List? value) { + public static List? CheckAdmins(List? value) { if (value is not null && value.Count == 0) { throw new ArgumentException("admins must be null or contain at least one UUID"); } else { diff --git a/src/ApiService/ApiService/QueueTaskHeartbeat.cs b/src/ApiService/ApiService/QueueTaskHeartbeat.cs index 174d2fafd..1f86dbe65 100644 --- a/src/ApiService/ApiService/QueueTaskHeartbeat.cs +++ b/src/ApiService/ApiService/QueueTaskHeartbeat.cs @@ -20,14 +20,14 @@ public class QueueTaskHearbeat { [Function("QueueTaskHeartbeat")] public async Async.Task Run([QueueTrigger("task-heartbeat", Connection = "AzureWebJobsStorage")] string msg) { - _logger.LogInformation($"heartbeat: {msg}"); + _logger.LogInformation("heartbeat: {Message}", msg); var hb = JsonSerializer.Deserialize(msg, EntityConverter.GetJsonSerializerOptions()).EnsureNotNull($"wrong data {msg}"); var task = await _tasks.GetByTaskId(hb.TaskId); if (task == null) { - _logger.LogWarning($"invalid task id: {hb.TaskId}"); + _logger.LogWarning("invalid task id: {TaskId}", hb.TaskId); return; } diff --git a/src/ApiService/ApiService/TimerDaily.cs b/src/ApiService/ApiService/TimerDaily.cs index a7426f640..f759e7797 100644 --- a/src/ApiService/ApiService/TimerDaily.cs +++ b/src/ApiService/ApiService/TimerDaily.cs @@ -21,7 +21,7 @@ public class TimerDaily { public async Async.Task Run([TimerTrigger("1.00:00:00")] TimerInfo myTimer) { var scalesets = _scalesets.Search(); await foreach (var scaleset in scalesets) { - _logger.LogInformation($"updating scaleset configs: {scaleset.ScalesetId}"); + _logger.LogInformation("updating scaleset configs: {ScaleSetId}", scaleset.ScalesetId); // todo: do it in batches await _scalesets.Replace(scaleset with { NeedsConfigUpdate = true }); } @@ -29,7 +29,7 @@ public class TimerDaily { var expiredWebhookLogs = _webhookMessageLogs.SearchExpired(); await foreach (var logEntry in expiredWebhookLogs) { - _logger.LogInformation($"stopping expired webhook message log: {logEntry.WebhookId}:{logEntry.EventId}"); + _logger.LogInformation("stopping expired webhook message log: {WebhookId}:{EventId}", logEntry.WebhookId, logEntry.EventId); await _webhookMessageLogs.Delete(logEntry); } } diff --git a/src/ApiService/ApiService/onefuzzlib/Config.cs b/src/ApiService/ApiService/onefuzzlib/Config.cs index a86c2a8a4..a6306995d 100644 --- a/src/ApiService/ApiService/onefuzzlib/Config.cs +++ b/src/ApiService/ApiService/onefuzzlib/Config.cs @@ -21,7 +21,7 @@ public class Config : IConfig { _queue = queue; } - private BlobContainerSasPermissions ConvertPermissions(ContainerPermission permission) { + private static BlobContainerSasPermissions ConvertPermissions(ContainerPermission permission) { BlobContainerSasPermissions blobPermissions = 0; if (permission.HasFlag(ContainerPermission.Read)) { blobPermissions |= BlobContainerSasPermissions.Read; diff --git a/src/ApiService/ApiService/onefuzzlib/Containers.cs b/src/ApiService/ApiService/onefuzzlib/Containers.cs index 30e8a6e46..3404370ac 100644 --- a/src/ApiService/ApiService/onefuzzlib/Containers.cs +++ b/src/ApiService/ApiService/onefuzzlib/Containers.cs @@ -14,7 +14,7 @@ public interface IContainers { public Async.Task FindContainer(Container container, StorageType storageType); public Async.Task GetFileSasUrl(Container container, string name, StorageType storageType, BlobSasPermissions permissions, TimeSpan? duration = null); - public Async.Task SaveBlob(Container container, string v1, string v2, StorageType config); + public Async.Task SaveBlob(Container container, string name, string data, StorageType storageType); public Async.Task GetInstanceId(); public Async.Task GetFileUrl(Container container, string name, StorageType storageType); @@ -125,7 +125,7 @@ public class Containers : IContainers { return sasUrl; } - public (DateTimeOffset, DateTimeOffset) SasTimeWindow(TimeSpan timeSpan) { + public static (DateTimeOffset, DateTimeOffset) SasTimeWindow(TimeSpan timeSpan) { // SAS URLs are valid 6 hours earlier, primarily to work around dev // workstations having out-of-sync time. Additionally, SAS URLs are stopped // 15 minutes later than requested based on "Be careful with SAS start time" @@ -149,7 +149,7 @@ public class Containers : IContainers { public Async.Task GetInstanceId() => _getInstanceId.Value; private readonly Lazy> _getInstanceId; - public Uri? GetContainerSasUrlService( + public static Uri? GetContainerSasUrlService( BlobContainerClient client, BlobSasPermissions permissions, bool tag = false, diff --git a/src/ApiService/ApiService/onefuzzlib/Defs.cs b/src/ApiService/ApiService/onefuzzlib/Defs.cs index 070872dbb..090dbcdc5 100644 --- a/src/ApiService/ApiService/onefuzzlib/Defs.cs +++ b/src/ApiService/ApiService/onefuzzlib/Defs.cs @@ -2,7 +2,7 @@ public static class Defs { - public static Dictionary TASK_DEFINITIONS = new Dictionary() { + public static readonly IReadOnlyDictionary TASK_DEFINITIONS = new Dictionary() { { TaskType.Coverage , new TaskDefinition( Features: new[] { diff --git a/src/ApiService/ApiService/onefuzzlib/Events.cs b/src/ApiService/ApiService/onefuzzlib/Events.cs index 05f4182b9..d15504bbc 100644 --- a/src/ApiService/ApiService/onefuzzlib/Events.cs +++ b/src/ApiService/ApiService/onefuzzlib/Events.cs @@ -35,9 +35,9 @@ namespace Microsoft.OneFuzz.Service { _creds = creds; } - public async Async.Task QueueSignalrEvent(EventMessage eventMessage) { - var message = new SignalREvent("events", new List() { eventMessage }); - await _queue.SendMessage("signalr-events", JsonSerializer.Serialize(message), StorageType.Config); + public async Async.Task QueueSignalrEvent(EventMessage message) { + var ev = new SignalREvent("events", new List() { message }); + await _queue.SendMessage("signalr-events", JsonSerializer.Serialize(ev), StorageType.Config); } public async Async.Task SendEvent(BaseEvent anEvent) { diff --git a/src/ApiService/ApiService/onefuzzlib/Extension.cs b/src/ApiService/ApiService/onefuzzlib/Extension.cs index 8dbef74a6..cb24b53e3 100644 --- a/src/ApiService/ApiService/onefuzzlib/Extension.cs +++ b/src/ApiService/ApiService/onefuzzlib/Extension.cs @@ -71,7 +71,7 @@ public class Extensions : IExtensions { return extensions; } - public VirtualMachineScaleSetExtensionData KeyVaultExtension(string region, KeyvaultExtensionConfig keyVault, Os vmOs) { + public static VirtualMachineScaleSetExtensionData KeyVaultExtension(string region, KeyvaultExtensionConfig keyVault, Os vmOs) { var keyVaultName = keyVault.KeyVaultName; var certName = keyVault.CertName; var uri = keyVaultName + certName; @@ -119,7 +119,7 @@ public class Extensions : IExtensions { } } - public VirtualMachineScaleSetExtensionData AzSecExtension(string region) { + public static VirtualMachineScaleSetExtensionData AzSecExtension(string region) { return new VirtualMachineScaleSetExtensionData { Name = "AzureSecurityLinuxAgent", Publisher = "Microsoft.Azure.Security.Monitoring", @@ -131,7 +131,7 @@ public class Extensions : IExtensions { } - public VirtualMachineScaleSetExtensionData AzMonExtension(string region, AzureMonitorExtensionConfig azureMonitor) { + public static VirtualMachineScaleSetExtensionData AzMonExtension(string region, AzureMonitorExtensionConfig azureMonitor) { var authId = azureMonitor.MonitoringGCSAuthId; var configVersion = azureMonitor.ConfigVersion; var moniker = azureMonitor.Moniker; @@ -164,7 +164,7 @@ public class Extensions : IExtensions { - public VirtualMachineScaleSetExtensionData GenevaExtension(string region) { + public static VirtualMachineScaleSetExtensionData GenevaExtension(string region) { return new VirtualMachineScaleSetExtensionData { Name = "Microsoft.Azure.Geneva.GenevaMonitoring", Publisher = "Microsoft.Azure.Geneva", @@ -175,7 +175,7 @@ public class Extensions : IExtensions { }; } - public VirtualMachineScaleSetExtensionData? DependencyExtension(string region, Os vmOs) { + public static VirtualMachineScaleSetExtensionData? DependencyExtension(string region, Os vmOs) { if (vmOs == Os.Windows) { return new VirtualMachineScaleSetExtensionData { diff --git a/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs b/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs index 633494c0c..5154a5273 100644 --- a/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/NodeOperations.cs @@ -41,8 +41,8 @@ public interface INodeOperations : IStatefulOrm { IAsyncEnumerable GetDeadNodes(Guid scaleSetId, TimeSpan expirationPeriod); Async.Task MarkTasksStoppedEarly(Node node, Error? error = null); - static TimeSpan NODE_EXPIRATION_TIME = TimeSpan.FromHours(1.0); - static TimeSpan NODE_REIMAGE_TIME = TimeSpan.FromDays(6.0); + static readonly TimeSpan NODE_EXPIRATION_TIME = TimeSpan.FromHours(1.0); + static readonly TimeSpan NODE_REIMAGE_TIME = TimeSpan.FromDays(6.0); Async.Task StopTask(Guid task_id); } diff --git a/src/ApiService/ApiService/onefuzzlib/PoolOperations.cs b/src/ApiService/ApiService/onefuzzlib/PoolOperations.cs index 9f291285e..886f09401 100644 --- a/src/ApiService/ApiService/onefuzzlib/PoolOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/PoolOperations.cs @@ -42,7 +42,6 @@ public class PoolOperations : StatefulOrm, IPoo return QueryAsync(filter: $"client_id eq '{clientId.ToString()}'"); } - private string GetPoolQueue(Pool pool) { - return $"pool-{pool.PoolId.ToString("N")}"; - } + private static string GetPoolQueue(Pool pool) + => $"pool-{pool.PoolId.ToString("N")}"; } diff --git a/src/ApiService/ApiService/onefuzzlib/Reports.cs b/src/ApiService/ApiService/onefuzzlib/Reports.cs index fa5fa7d40..42fda88b6 100644 --- a/src/ApiService/ApiService/onefuzzlib/Reports.cs +++ b/src/ApiService/ApiService/onefuzzlib/Reports.cs @@ -17,7 +17,7 @@ public class Reports : IReports { public async Async.Task GetReportOrRegression(Container container, string fileName, bool expectReports = false, params string[] args) { var filePath = String.Join("/", new[] { container.ContainerName, fileName }); - if (!fileName.EndsWith(".json")) { + if (!fileName.EndsWith(".json", StringComparison.Ordinal)) { if (expectReports) { _log.Error($"get_report invalid extension: {filePath}"); } diff --git a/src/ApiService/ApiService/onefuzzlib/ReproOperations.cs b/src/ApiService/ApiService/onefuzzlib/ReproOperations.cs index f2c2e8eed..fd78ce42f 100644 --- a/src/ApiService/ApiService/onefuzzlib/ReproOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/ReproOperations.cs @@ -7,7 +7,7 @@ public interface IReproOperations : IStatefulOrm { public Async.Task Stopping(Repro repro); - public IAsyncEnumerable SearchStates(IEnumerable? States); + public IAsyncEnumerable SearchStates(IEnumerable? states); } public class ReproOperations : StatefulOrm, IReproOperations { diff --git a/src/ApiService/ApiService/onefuzzlib/VmOperations.cs b/src/ApiService/ApiService/onefuzzlib/VmOperations.cs index 39a443728..2e7a1967a 100644 --- a/src/ApiService/ApiService/onefuzzlib/VmOperations.cs +++ b/src/ApiService/ApiService/onefuzzlib/VmOperations.cs @@ -53,7 +53,7 @@ public class VmOperations : IVmOperations { var disks = await _diskOperations.ListDisks(resourceGroup) .ToAsyncEnumerable() - .Where(disk => disk.Data.Name.StartsWith(name)) + .Where(disk => disk.Data.Name.StartsWith(name, StringComparison.Ordinal)) .AnyAsync(); if (disks) { @@ -99,7 +99,7 @@ public class VmOperations : IVmOperations { var disks = _diskOperations.ListDisks(resourceGroup) .ToAsyncEnumerable() - .Where(disk => disk.Data.Name.StartsWith(name)); + .Where(disk => disk.Data.Name.StartsWith(name, StringComparison.Ordinal)); if (await disks.AnyAsync()) { await foreach (var disk in disks) { diff --git a/src/ApiService/ApiService/onefuzzlib/orm/CaseConverter.cs b/src/ApiService/ApiService/onefuzzlib/orm/CaseConverter.cs index bba360c58..d9a1ab484 100644 --- a/src/ApiService/ApiService/onefuzzlib/orm/CaseConverter.cs +++ b/src/ApiService/ApiService/onefuzzlib/orm/CaseConverter.cs @@ -1,4 +1,6 @@ -namespace Microsoft.OneFuzz.Service.OneFuzzLib.Orm; +using System.Globalization; + +namespace Microsoft.OneFuzz.Service.OneFuzzLib.Orm; public class CaseConverter { /// get the start indices of each word and the lat indice @@ -37,6 +39,7 @@ public class CaseConverter { } public static string SnakeToPascal(string input) { - return string.Join("", input.Split('_', StringSplitOptions.RemoveEmptyEntries).Select(x => $"{Char.ToUpper(x[0])}{x.Substring(1)}")); + var ti = CultureInfo.InvariantCulture.TextInfo; + return string.Concat(input.Split('_', StringSplitOptions.RemoveEmptyEntries).Select(x => ti.ToTitleCase(x))); } } diff --git a/src/ApiService/ApiService/onefuzzlib/orm/CustomConverterFactory.cs b/src/ApiService/ApiService/onefuzzlib/orm/CustomConverterFactory.cs index 42c6ea89e..dfe45530a 100644 --- a/src/ApiService/ApiService/onefuzzlib/orm/CustomConverterFactory.cs +++ b/src/ApiService/ApiService/onefuzzlib/orm/CustomConverterFactory.cs @@ -51,7 +51,7 @@ public sealed class CustomEnumConverter : JsonConverter where T : Enum { } var type = typeof(T); - _skipFormat = type.GetCustomAttribute() != null; + _skipFormat = type.GetCustomAttribute() != null; if (continueProcessing) { Array values = Enum.GetValues(type); @@ -102,7 +102,7 @@ public sealed class CustomEnumConverter : JsonConverter where T : Enum { if (!_writeCache.TryGetValue(value, out JsonEncodedText formatted)) { if (_writeCache.Count == NameCacheLimit) { Debug.Assert(_readCache.Count == NameCacheLimit); - throw new ArgumentOutOfRangeException(); + throw new InvalidOperationException("Hit cache limit"); } formatted = FormatAndAddToCaches(value, options.Encoder, _skipFormat); @@ -118,7 +118,7 @@ public sealed class CustomEnumConverter : JsonConverter where T : Enum { return valueEncoded; } - private ValueTuple FormatEnumValue(string value, JsonNamingPolicy namingPolicy, JavaScriptEncoder? encoder, bool skipFormat = false) { + private static ValueTuple FormatEnumValue(string value, JsonNamingPolicy namingPolicy, JavaScriptEncoder? encoder, bool skipFormat = false) { string converted; if (!value.Contains(ValueSeparator)) { @@ -195,7 +195,7 @@ public sealed class PolymorphicConverter : JsonConverter { public PolymorphicConverter(TypeDiscrimnatorAttribute typeDiscriminator, string discriminatedField) : base() { _discriminatorField = typeDiscriminator.FieldName; - _typeProvider = (ITypeProvider)(typeDiscriminator.ConverterType.GetConstructor(new Type[] { })?.Invoke(null) ?? throw new JsonException()); + _typeProvider = (ITypeProvider)(Activator.CreateInstance(typeDiscriminator.ConverterType) ?? throw new JsonException()); _discriminatedField = discriminatedField; _constructorInfo = typeof(T).GetConstructors().FirstOrDefault() ?? throw new JsonException("No Constructor found"); _parameters = _constructorInfo.GetParameters()?.ToDictionary(x => x.Name ?? "") ?? throw new JsonException(); diff --git a/src/ApiService/ApiService/onefuzzlib/orm/EntityConverter.cs b/src/ApiService/ApiService/onefuzzlib/orm/EntityConverter.cs index 306ff0665..617680d32 100644 --- a/src/ApiService/ApiService/onefuzzlib/orm/EntityConverter.cs +++ b/src/ApiService/ApiService/onefuzzlib/orm/EntityConverter.cs @@ -26,9 +26,12 @@ public class SerializeValueAttribute : Attribute { } /// Indicates that the enum cases should no be renamed [AttributeUsage(AttributeTargets.Enum)] -public class SkipRename : Attribute { } +public class SkipRenameAttribute : Attribute { } +[AttributeUsage(AttributeTargets.Parameter)] public class RowKeyAttribute : Attribute { } +[AttributeUsage(AttributeTargets.Parameter)] public class PartitionKeyAttribute : Attribute { } +[AttributeUsage(AttributeTargets.Property)] public class TypeDiscrimnatorAttribute : Attribute { public string FieldName { get; } // the type of a function that takes the value of fieldName as an input and return the type @@ -66,15 +69,11 @@ public class EntityConverter { private readonly ConcurrentDictionary _cache; - private readonly ETag _emptyETag = new ETag(); - public EntityConverter() { _options = GetJsonSerializerOptions(); _cache = new ConcurrentDictionary(); - } - public static JsonSerializerOptions GetJsonSerializerOptions() { var options = new JsonSerializerOptions() { PropertyNamingPolicy = new OnefuzzNamingPolicy(), @@ -102,7 +101,7 @@ public class EntityConverter { return ctor; } - private IEnumerable GetEntityProperties(ParameterInfo parameterInfo) { + private static IEnumerable GetEntityProperties(ParameterInfo parameterInfo) { var name = parameterInfo.Name.EnsureNotNull($"Invalid paramter {parameterInfo}"); var parameterType = parameterInfo.ParameterType.EnsureNotNull($"Invalid paramter {parameterInfo}"); var isRowkey = parameterInfo.GetCustomAttribute(typeof(RowKeyAttribute)) != null; @@ -112,7 +111,7 @@ public class EntityConverter { (TypeDiscrimnatorAttribute, ITypeProvider)? discriminator = null; if (discriminatorAttribute != null) { - var t = (ITypeProvider)(discriminatorAttribute.ConverterType.GetConstructor(new Type[] { })?.Invoke(null) ?? throw new Exception("unable to retrive the type provider")); + var t = (ITypeProvider)(Activator.CreateInstance(discriminatorAttribute.ConverterType) ?? throw new Exception("unable to retrive the type provider")); discriminator = (discriminatorAttribute, t); } @@ -149,13 +148,11 @@ public class EntityConverter { public TableEntity ToTableEntity(T typedEntity) where T : EntityBase { if (typedEntity == null) { - throw new NullReferenceException(); - } - var type = typeof(T)!; - if (type is null) { - throw new NullReferenceException(); + throw new ArgumentNullException(nameof(typedEntity)); } + var type = typeof(T); + var entityInfo = GetEntityInfo(); Dictionary columnValues = entityInfo.properties.SelectMany(x => x).Select(prop => { var value = entityInfo.type.GetProperty(prop.name)?.GetValue(typedEntity); @@ -270,7 +267,7 @@ public class EntityConverter { entityInfo.properties.Select(grouping => GetFieldValue(entityInfo, grouping.Key, entity)).ToArray(); try { var entityRecord = (T)entityInfo.constructor.Invoke(parameters); - if (entity.ETag != _emptyETag) { + if (entity.ETag != default) { entityRecord.ETag = entity.ETag; } entityRecord.TimeStamp = entity.Timestamp; diff --git a/src/ApiService/ApiService/onefuzzlib/orm/Orm.cs b/src/ApiService/ApiService/onefuzzlib/orm/Orm.cs index 6dc0edd18..7555d3397 100644 --- a/src/ApiService/ApiService/onefuzzlib/orm/Orm.cs +++ b/src/ApiService/ApiService/onefuzzlib/orm/Orm.cs @@ -27,9 +27,11 @@ namespace ApiService.OneFuzzLib.Orm { public class Orm : IOrm where T : EntityBase { +#pragma warning disable CA1051 // permit visible instance fields protected readonly EntityConverter _entityConverter; protected readonly IOnefuzzContext _context; protected readonly ILogTracer _logTracer; +#pragma warning restore CA1051 public Orm(ILogTracer logTracer, IOnefuzzContext context) { @@ -136,7 +138,7 @@ namespace ApiService.OneFuzzLib.Orm { } - public class StatefulOrm : Orm, IStatefulOrm where T : StatefulEntityBase where TState : Enum { + public class StatefulOrm : Orm, IStatefulOrm where T : StatefulEntityBase where TState : Enum { static Lazy>? _partitionKeyGetter; static Lazy>? _rowKeyGetter; static ConcurrentDictionary>?> _stateFuncs = new ConcurrentDictionary>?>(); @@ -147,7 +149,7 @@ namespace ApiService.OneFuzzLib.Orm { static StatefulOrm() { /// verify that all state transition function have the correct signature: - var thisType = typeof(Self); + var thisType = typeof(TSelf); var states = Enum.GetNames(typeof(TState)); var delegateType = typeof(StateTransition); MethodInfo delegateSignature = delegateType.GetMethod("Invoke")!; diff --git a/src/ApiService/Directory.Build.props b/src/ApiService/Directory.Build.props index c41f6ead9..d39ac27d3 100644 --- a/src/ApiService/Directory.Build.props +++ b/src/ApiService/Directory.Build.props @@ -4,10 +4,19 @@ net6.0 + + + true + true - 6.0-Default - + 6.0-Recommended enable diff --git a/src/ApiService/IntegrationTests/_FunctionTestBase.cs b/src/ApiService/IntegrationTests/_FunctionTestBase.cs index 6d87c2da7..184896a26 100644 --- a/src/ApiService/IntegrationTests/_FunctionTestBase.cs +++ b/src/ApiService/IntegrationTests/_FunctionTestBase.cs @@ -65,6 +65,8 @@ public abstract class FunctionTestBase : IDisposable { => new EntityConverter().FromJsonString(BodyAsString(data)) ?? throw new Exception($"unable to deserialize body as {typeof(T)}"); public void Dispose() { + GC.SuppressFinalize(this); + var (accountName, accountKey) = _storage.GetStorageAccountNameAndKey("").Result; // sync for test impls if (accountName is not null && accountKey is not null) { // clean up any tables & blobs that this test created diff --git a/src/ApiService/Tests/OrmModelsTest.cs b/src/ApiService/Tests/OrmModelsTest.cs index 31f989e2a..87c0c920a 100644 --- a/src/ApiService/Tests/OrmModelsTest.cs +++ b/src/ApiService/Tests/OrmModelsTest.cs @@ -439,19 +439,20 @@ namespace Tests { typeof(SecureString) }); static bool IEnumerableEqual(IEnumerable? a, IEnumerable? b) { - if (a is null && b is null) { - return true; + if (a is null) { + return b is null; } - if (a!.Count() != b!.Count()) { + + if (b is null) { return false; } - if (a!.Count() == 0 && b!.Count() == 0) { - return true; + if (a.Count() != b.Count()) { + return false; } - foreach (var v in a!.Zip(b!)) { - if (!AreEqual(v.First, v.Second)) { + foreach (var (first, second) in a.Zip(b)) { + if (!AreEqual(first, second)) { return false; } } diff --git a/src/ApiService/Tests/SchedulerTests.cs b/src/ApiService/Tests/SchedulerTests.cs index 3918f1775..78aba6e8e 100644 --- a/src/ApiService/Tests/SchedulerTests.cs +++ b/src/ApiService/Tests/SchedulerTests.cs @@ -8,7 +8,7 @@ namespace Tests; public class SchedulerTests { - IEnumerable BuildTasks(int size) { + static IEnumerable BuildTasks(int size) { return Enumerable.Range(0, size).Select(i => new Task( Guid.Empty, @@ -123,7 +123,7 @@ public class SchedulerTests { CheckBuckets(buckets, tasks, 12); } - void CheckBuckets(ILookup buckets, List tasks, int bucketCount) { + static void CheckBuckets(ILookup buckets, List tasks, int bucketCount) { Assert.Equal(buckets.Count, bucketCount); foreach (var task in tasks) {