From 3c2b5b6aa0e92a1c7a8315585d5a530b1349d81c Mon Sep 17 00:00:00 2001 From: Siri Varma Vegiraju Date: Thu, 27 Feb 2025 14:51:40 -0800 Subject: [PATCH 01/10] Add Analyzer Signed-off-by: Siri Varma Vegiraju --- Directory.Packages.props | 1 + all.sln | 21 +++ .../AnalyzerReleases.Shipped.md | 7 + .../AnalyzerReleases.Unshipped.md | 3 + .../Dapr.Jobs.Analyzer.csproj | 35 +++++ .../DaprJobsAnalyzerAnalyzer.cs | 87 ++++++++++++ src/Dapr.Jobs.Analyzer/Resources.Designer.cs | 106 ++++++++++++++ src/Dapr.Jobs.Analyzer/Resources.resx | 132 ++++++++++++++++++ .../Dapr.Jobs.Analyzer.Test.csproj | 35 +++++ .../DaprJobsAnalyzerUnitTests.cs | 59 ++++++++ .../CSharpAnalyzerVerifier`1+Test.cs | 26 ++++ .../Verifiers/CSharpAnalyzerVerifier`1.cs | 38 +++++ .../Verifiers/CSharpCodeFixVerifier`2+Test.cs | 28 ++++ .../Verifiers/CSharpCodeFixVerifier`2.cs | 61 ++++++++ .../CSharpCodeRefactoringVerifier`1+Test.cs | 26 ++++ .../CSharpCodeRefactoringVerifier`1.cs | 36 +++++ .../Verifiers/CSharpVerifierHelper.cs | 33 +++++ .../VisualBasicAnalyzerVerifier`1+Test.cs | 17 +++ .../VisualBasicAnalyzerVerifier`1.cs | 38 +++++ .../VisualBasicCodeFixVerifier`2+Test.cs | 16 +++ .../Verifiers/VisualBasicCodeFixVerifier`2.cs | 61 ++++++++ ...sualBasicCodeRefactoringVerifier`1+Test.cs | 14 ++ .../VisualBasicCodeRefactoringVerifier`1.cs | 36 +++++ 23 files changed, 916 insertions(+) create mode 100644 src/Dapr.Jobs.Analyzer/AnalyzerReleases.Shipped.md create mode 100644 src/Dapr.Jobs.Analyzer/AnalyzerReleases.Unshipped.md create mode 100644 src/Dapr.Jobs.Analyzer/Dapr.Jobs.Analyzer.csproj create mode 100644 src/Dapr.Jobs.Analyzer/DaprJobsAnalyzerAnalyzer.cs create mode 100644 src/Dapr.Jobs.Analyzer/Resources.Designer.cs create mode 100644 src/Dapr.Jobs.Analyzer/Resources.resx create mode 100644 test/Dapr.Jobs.Analyzer.Test/Dapr.Jobs.Analyzer.Test.csproj create mode 100644 test/Dapr.Jobs.Analyzer.Test/DaprJobsAnalyzerUnitTests.cs create mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1+Test.cs create mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1.cs create mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2+Test.cs create mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2.cs create mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1+Test.cs create mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1.cs create mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpVerifierHelper.cs create mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1+Test.cs create mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1.cs create mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2+Test.cs create mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2.cs create mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1+Test.cs create mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1.cs diff --git a/Directory.Packages.props b/Directory.Packages.props index e249a871f..873a5fc7d 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -20,6 +20,7 @@ + diff --git a/all.sln b/all.sln index 9a163b1d9..dfed8c941 100644 --- a/all.sln +++ b/all.sln @@ -155,6 +155,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JobsSample", "examples\Jobs EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Workflow.Test", "test\Dapr.Workflow.Test\Dapr.Workflow.Test.csproj", "{E90114C6-86FC-43B8-AE5C-D9273CF21FE4}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Jobs.Analyzer", "src\Dapr.Jobs.Analyzer\Dapr.Jobs.Analyzer.csproj", "{28B87C37-4B52-400F-B84D-64F134931BDC}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Jobs.Analyzer.Test", "test\Dapr.Jobs.Analyzer.Test\Dapr.Jobs.Analyzer.Test.csproj", "{CADEAE45-8981-4723-B641-9C28251C7D3B}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Jobs.Analyzer.Vsix", "src\Dapr.Jobs.Analyzer\Dapr.Jobs.Analyzer.Vsix\Dapr.Jobs.Analyzer.Vsix.csproj", "{0C3D3AE2-8A32-4683-992B-5FC37C4B644D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -403,6 +409,18 @@ Global {E90114C6-86FC-43B8-AE5C-D9273CF21FE4}.Debug|Any CPU.Build.0 = Debug|Any CPU {E90114C6-86FC-43B8-AE5C-D9273CF21FE4}.Release|Any CPU.ActiveCfg = Release|Any CPU {E90114C6-86FC-43B8-AE5C-D9273CF21FE4}.Release|Any CPU.Build.0 = Release|Any CPU + {28B87C37-4B52-400F-B84D-64F134931BDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {28B87C37-4B52-400F-B84D-64F134931BDC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {28B87C37-4B52-400F-B84D-64F134931BDC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {28B87C37-4B52-400F-B84D-64F134931BDC}.Release|Any CPU.Build.0 = Release|Any CPU + {CADEAE45-8981-4723-B641-9C28251C7D3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CADEAE45-8981-4723-B641-9C28251C7D3B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CADEAE45-8981-4723-B641-9C28251C7D3B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CADEAE45-8981-4723-B641-9C28251C7D3B}.Release|Any CPU.Build.0 = Release|Any CPU + {0C3D3AE2-8A32-4683-992B-5FC37C4B644D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0C3D3AE2-8A32-4683-992B-5FC37C4B644D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0C3D3AE2-8A32-4683-992B-5FC37C4B644D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0C3D3AE2-8A32-4683-992B-5FC37C4B644D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -477,6 +495,9 @@ Global {D9697361-232F-465D-A136-4561E0E88488} = {D687DDC4-66C5-4667-9E3A-FD8B78ECAA78} {9CAF360E-5AD3-4C4F-89A0-327EEB70D673} = {D9697361-232F-465D-A136-4561E0E88488} {E90114C6-86FC-43B8-AE5C-D9273CF21FE4} = {DD020B34-460F-455F-8D17-CF4A949F100B} + {28B87C37-4B52-400F-B84D-64F134931BDC} = {27C5D71D-0721-4221-9286-B94AB07B58CF} + {CADEAE45-8981-4723-B641-9C28251C7D3B} = {DD020B34-460F-455F-8D17-CF4A949F100B} + {0C3D3AE2-8A32-4683-992B-5FC37C4B644D} = {27C5D71D-0721-4221-9286-B94AB07B58CF} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {65220BF2-EAE1-4CB2-AA58-EBE80768CB40} diff --git a/src/Dapr.Jobs.Analyzer/AnalyzerReleases.Shipped.md b/src/Dapr.Jobs.Analyzer/AnalyzerReleases.Shipped.md new file mode 100644 index 000000000..7725e6165 --- /dev/null +++ b/src/Dapr.Jobs.Analyzer/AnalyzerReleases.Shipped.md @@ -0,0 +1,7 @@ +## Release 1.16 + +### New Rules + +Rule ID | Category | Severity | Notes +--------|----------|----------|-------------------- +DAPRJOBS0001| Usage | Warning | The method 'MapDaprScheduledJobHandler' should be called on 'app' in startup configuration \ No newline at end of file diff --git a/src/Dapr.Jobs.Analyzer/AnalyzerReleases.Unshipped.md b/src/Dapr.Jobs.Analyzer/AnalyzerReleases.Unshipped.md new file mode 100644 index 000000000..b1b99aaf2 --- /dev/null +++ b/src/Dapr.Jobs.Analyzer/AnalyzerReleases.Unshipped.md @@ -0,0 +1,3 @@ +; Unshipped analyzer release +; https://github.com/dotnet/roslyn-analyzers/blob/main/src/Microsoft.CodeAnalysis.Analyzers/ReleaseTrackingAnalyzers.Help.md + diff --git a/src/Dapr.Jobs.Analyzer/Dapr.Jobs.Analyzer.csproj b/src/Dapr.Jobs.Analyzer/Dapr.Jobs.Analyzer.csproj new file mode 100644 index 000000000..647fe7b51 --- /dev/null +++ b/src/Dapr.Jobs.Analyzer/Dapr.Jobs.Analyzer.csproj @@ -0,0 +1,35 @@ + + + + netstandard2.0 + false + + + *$(MSBuildProjectFile)* + true + + + + + + + + + true + + + false + + + false + + + This package contains Roslyn analyzers for actors. + $(PackageTags) + + + + + + + diff --git a/src/Dapr.Jobs.Analyzer/DaprJobsAnalyzerAnalyzer.cs b/src/Dapr.Jobs.Analyzer/DaprJobsAnalyzerAnalyzer.cs new file mode 100644 index 000000000..e5e36964f --- /dev/null +++ b/src/Dapr.Jobs.Analyzer/DaprJobsAnalyzerAnalyzer.cs @@ -0,0 +1,87 @@ +using System.Collections.Immutable; +using System.Linq; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using Microsoft.CodeAnalysis.Diagnostics; + +namespace Dapr.Jobs.Analyzer +{ + /// + /// DaprJobsAnalyzerAnalyzer. + /// + [DiagnosticAnalyzer(LanguageNames.CSharp)] + public class DaprJobsAnalyzerAnalyzer : DiagnosticAnalyzer + { + private static readonly DiagnosticDescriptor DaprJobHandlerRule = new DiagnosticDescriptor( + id: "DAPRJOBS0001", + title: "Ensure Post Mapper handler is present for all the Scheduled Jobs", + messageFormat: "There should be a mapping post endpoint for each scheduled job to make sure app receives notifications for all the scheduled jobs", + category: "Usage", + DiagnosticSeverity.Warning, + isEnabledByDefault: true + ); + + /// + public override ImmutableArray SupportedDiagnostics { get { return ImmutableArray.Create(DaprJobHandlerRule); } } + + /// + public override void Initialize(AnalysisContext context) + { + context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); + context.EnableConcurrentExecution(); + + context.RegisterSyntaxNodeAction(AnalyzeJobSchedulerHandler, SyntaxKind.InvocationExpression); + } + + private static void AnalyzeJobSchedulerHandler(SyntaxNodeAnalysisContext context) + { + var invocationExpression = (InvocationExpressionSyntax)context.Node; + + var memberAccess = invocationExpression.Expression as MemberAccessExpressionSyntax; + if (memberAccess?.Name.ToString() == "ScheduleJobAsync") + { + var arguments = invocationExpression.ArgumentList.Arguments; + if (arguments.Count == 1 && arguments[0].Expression is LiteralExpressionSyntax literal) + { + string jobName = literal.Token.ValueText; + + // Now, we will check for a corresponding endpoint route. + CheckForEndpointRoute(context, jobName); + } + } + } + + private static void CheckForEndpointRoute(SyntaxNodeAnalysisContext context, string jobName) + { + var root = context.SemanticModel.SyntaxTree.GetRoot(); + + // Search for MapPost with the corresponding route + var endpointMappings = root.DescendantNodes() + .OfType() + .Where(invocation => invocation.Expression.ToString().Contains("MapPost")) + .ToList(); + + foreach (var mapping in endpointMappings) + { + // Look for route patterns like "/job/{jobname}" + var argument = mapping.ArgumentList.Arguments.FirstOrDefault()?.ToString(); + + if (argument != null) + { + string[] endpointSplit = argument.Split('/'); + if (endpointSplit.Length == 3 + && endpointSplit[1].Equals("job") + && (endpointSplit[2].Equals(jobName) || ((endpointSplit[2].StartsWith("{") && endpointSplit[2].EndsWith("}"))))) + { + return; + } + } + } + + // If no matching route was found, report a diagnostic + var diagnostic = Diagnostic.Create(DaprJobHandlerRule, context.Node.GetLocation(), jobName); + context.ReportDiagnostic(diagnostic); + } + } +} diff --git a/src/Dapr.Jobs.Analyzer/Resources.Designer.cs b/src/Dapr.Jobs.Analyzer/Resources.Designer.cs new file mode 100644 index 000000000..47d18d5ab --- /dev/null +++ b/src/Dapr.Jobs.Analyzer/Resources.Designer.cs @@ -0,0 +1,106 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.0 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Dapr.Jobs.Analyzer +{ + using System; + using System.Reflection; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if (object.ReferenceEquals(resourceMan, null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Dapr.Jobs.Analyzer.Resources", typeof(Resources).GetTypeInfo().Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Type names should be all uppercase.. + /// + internal static string AnalyzerDescription + { + get + { + return ResourceManager.GetString("AnalyzerDescription", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type name '{0}' contains lowercase letters. + /// + internal static string AnalyzerMessageFormat + { + get + { + return ResourceManager.GetString("AnalyzerMessageFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type name contains lowercase letters. + /// + internal static string AnalyzerTitle + { + get + { + return ResourceManager.GetString("AnalyzerTitle", resourceCulture); + } + } + } +} diff --git a/src/Dapr.Jobs.Analyzer/Resources.resx b/src/Dapr.Jobs.Analyzer/Resources.resx new file mode 100644 index 000000000..410edccd7 --- /dev/null +++ b/src/Dapr.Jobs.Analyzer/Resources.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Type names should be all uppercase. + An optional longer localizable description of the diagnostic. + + + Type name '{0}' contains lowercase letters + The format-able message the diagnostic displays. + + + Type name contains lowercase letters + The title of the diagnostic. + + \ No newline at end of file diff --git a/test/Dapr.Jobs.Analyzer.Test/Dapr.Jobs.Analyzer.Test.csproj b/test/Dapr.Jobs.Analyzer.Test/Dapr.Jobs.Analyzer.Test.csproj new file mode 100644 index 000000000..838577171 --- /dev/null +++ b/test/Dapr.Jobs.Analyzer.Test/Dapr.Jobs.Analyzer.Test.csproj @@ -0,0 +1,35 @@ + + + + netcoreapp3.1 + enable + enable + false + true + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + + + + diff --git a/test/Dapr.Jobs.Analyzer.Test/DaprJobsAnalyzerUnitTests.cs b/test/Dapr.Jobs.Analyzer.Test/DaprJobsAnalyzerUnitTests.cs new file mode 100644 index 000000000..1927755ed --- /dev/null +++ b/test/Dapr.Jobs.Analyzer.Test/DaprJobsAnalyzerUnitTests.cs @@ -0,0 +1,59 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Threading.Tasks; +using VerifyCS = Dapr.Jobs.Analyzer.Test.CSharpCodeFixVerifier< + Dapr.Jobs.Analyzer.DaprJobsAnalyzerAnalyzer, + Dapr.Jobs.Analyzer.DaprJobsAnalyzerCodeFixProvider>; + +namespace Dapr.Jobs.Analyzer.Test +{ + [TestClass] + public class DaprJobsAnalyzerUnitTest + { + //No diagnostics expected to show up + [TestMethod] + public async Task TestMethod1() + { + var test = @""; + + await VerifyCS.VerifyAnalyzerAsync(test); + } + + //Diagnostic and CodeFix both triggered and checked for + [TestMethod] + public async Task TestMethod2() + { + var test = @" + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + using System.Diagnostics; + + namespace ConsoleApplication1 + { + class {|#0:TypeName|} + { + } + }"; + + var fixtest = @" + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + using System.Threading.Tasks; + using System.Diagnostics; + + namespace ConsoleApplication1 + { + class TYPENAME + { + } + }"; + + var expected = VerifyCS.Diagnostic("DaprJobsAnalyzer").WithLocation(0).WithArguments("TypeName"); + await VerifyCS.VerifyCodeFixAsync(test, expected, fixtest); + } + } +} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1+Test.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1+Test.cs new file mode 100644 index 000000000..7a79e589c --- /dev/null +++ b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1+Test.cs @@ -0,0 +1,26 @@ +using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing.Verifiers; + +namespace Dapr.Jobs.Analyzer.Test +{ + public static partial class CSharpAnalyzerVerifier + where TAnalyzer : DiagnosticAnalyzer, new() + { + public class Test : CSharpAnalyzerTest + { + public Test() + { + SolutionTransforms.Add((solution, projectId) => + { + var compilationOptions = solution.GetProject(projectId).CompilationOptions; + compilationOptions = compilationOptions.WithSpecificDiagnosticOptions( + compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings)); + solution = solution.WithProjectCompilationOptions(projectId, compilationOptions); + + return solution; + }); + } + } + } +} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1.cs new file mode 100644 index 000000000..4fcf72386 --- /dev/null +++ b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1.cs @@ -0,0 +1,38 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Testing.Verifiers; + +namespace Dapr.Jobs.Analyzer.Test +{ + public static partial class CSharpAnalyzerVerifier + where TAnalyzer : DiagnosticAnalyzer, new() + { + /// + public static DiagnosticResult Diagnostic() + => CSharpAnalyzerVerifier.Diagnostic(); + + /// + public static DiagnosticResult Diagnostic(string diagnosticId) + => CSharpAnalyzerVerifier.Diagnostic(diagnosticId); + + /// + public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor) + => CSharpAnalyzerVerifier.Diagnostic(descriptor); + + /// + public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected) + { + var test = new Test + { + TestCode = source, + }; + + test.ExpectedDiagnostics.AddRange(expected); + await test.RunAsync(CancellationToken.None); + } + } +} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2+Test.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2+Test.cs new file mode 100644 index 000000000..c0a98b754 --- /dev/null +++ b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2+Test.cs @@ -0,0 +1,28 @@ +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing.Verifiers; + +namespace Dapr.Jobs.Analyzer.Test +{ + public static partial class CSharpCodeFixVerifier + where TAnalyzer : DiagnosticAnalyzer, new() + where TCodeFix : CodeFixProvider, new() + { + public class Test : CSharpCodeFixTest + { + public Test() + { + SolutionTransforms.Add((solution, projectId) => + { + var compilationOptions = solution.GetProject(projectId).CompilationOptions; + compilationOptions = compilationOptions.WithSpecificDiagnosticOptions( + compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings)); + solution = solution.WithProjectCompilationOptions(projectId, compilationOptions); + + return solution; + }); + } + } + } +} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2.cs new file mode 100644 index 000000000..4bb1e0b4f --- /dev/null +++ b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2.cs @@ -0,0 +1,61 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Testing.Verifiers; + +namespace Dapr.Jobs.Analyzer.Test +{ + public static partial class CSharpCodeFixVerifier + where TAnalyzer : DiagnosticAnalyzer, new() + where TCodeFix : CodeFixProvider, new() + { + /// + public static DiagnosticResult Diagnostic() + => CSharpCodeFixVerifier.Diagnostic(); + + /// + public static DiagnosticResult Diagnostic(string diagnosticId) + => CSharpCodeFixVerifier.Diagnostic(diagnosticId); + + /// + public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor) + => CSharpCodeFixVerifier.Diagnostic(descriptor); + + /// + public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected) + { + var test = new Test + { + TestCode = source, + }; + + test.ExpectedDiagnostics.AddRange(expected); + await test.RunAsync(CancellationToken.None); + } + + /// + public static async Task VerifyCodeFixAsync(string source, string fixedSource) + => await VerifyCodeFixAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource); + + /// + public static async Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource) + => await VerifyCodeFixAsync(source, new[] { expected }, fixedSource); + + /// + public static async Task VerifyCodeFixAsync(string source, DiagnosticResult[] expected, string fixedSource) + { + var test = new Test + { + TestCode = source, + FixedCode = fixedSource, + }; + + test.ExpectedDiagnostics.AddRange(expected); + await test.RunAsync(CancellationToken.None); + } + } +} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1+Test.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1+Test.cs new file mode 100644 index 000000000..25b37ff6c --- /dev/null +++ b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1+Test.cs @@ -0,0 +1,26 @@ +using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.CSharp.Testing; +using Microsoft.CodeAnalysis.Testing.Verifiers; + +namespace Dapr.Jobs.Analyzer.Test +{ + public static partial class CSharpCodeRefactoringVerifier + where TCodeRefactoring : CodeRefactoringProvider, new() + { + public class Test : CSharpCodeRefactoringTest + { + public Test() + { + SolutionTransforms.Add((solution, projectId) => + { + var compilationOptions = solution.GetProject(projectId).CompilationOptions; + compilationOptions = compilationOptions.WithSpecificDiagnosticOptions( + compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings)); + solution = solution.WithProjectCompilationOptions(projectId, compilationOptions); + + return solution; + }); + } + } + } +} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1.cs new file mode 100644 index 000000000..705f691eb --- /dev/null +++ b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1.cs @@ -0,0 +1,36 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.Testing; + +namespace Dapr.Jobs.Analyzer.Test +{ + public static partial class CSharpCodeRefactoringVerifier + where TCodeRefactoring : CodeRefactoringProvider, new() + { + /// + public static async Task VerifyRefactoringAsync(string source, string fixedSource) + { + await VerifyRefactoringAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource); + } + + /// + public static async Task VerifyRefactoringAsync(string source, DiagnosticResult expected, string fixedSource) + { + await VerifyRefactoringAsync(source, new[] { expected }, fixedSource); + } + + /// + public static async Task VerifyRefactoringAsync(string source, DiagnosticResult[] expected, string fixedSource) + { + var test = new Test + { + TestCode = source, + FixedCode = fixedSource, + }; + + test.ExpectedDiagnostics.AddRange(expected); + await test.RunAsync(CancellationToken.None); + } + } +} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpVerifierHelper.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpVerifierHelper.cs new file mode 100644 index 000000000..d9875afe8 --- /dev/null +++ b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpVerifierHelper.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Immutable; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; + +namespace Dapr.Jobs.Analyzer.Test +{ + internal static class CSharpVerifierHelper + { + /// + /// By default, the compiler reports diagnostics for nullable reference types at + /// , and the analyzer test framework defaults to only validating + /// diagnostics at . This map contains all compiler diagnostic IDs + /// related to nullability mapped to , which is then used to enable all + /// of these warnings for default validation during analyzer and code fix tests. + /// + internal static ImmutableDictionary NullableWarnings { get; } = GetNullableWarningsFromCompiler(); + + private static ImmutableDictionary GetNullableWarningsFromCompiler() + { + string[] args = { "/warnaserror:nullable" }; + var commandLineArguments = CSharpCommandLineParser.Default.Parse(args, baseDirectory: Environment.CurrentDirectory, sdkDirectory: Environment.CurrentDirectory); + var nullableWarnings = commandLineArguments.CompilationOptions.SpecificDiagnosticOptions; + + // Workaround for https://github.com/dotnet/roslyn/issues/41610 + nullableWarnings = nullableWarnings + .SetItem("CS8632", ReportDiagnostic.Error) + .SetItem("CS8669", ReportDiagnostic.Error); + + return nullableWarnings; + } + } +} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1+Test.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1+Test.cs new file mode 100644 index 000000000..25cc5ab7c --- /dev/null +++ b/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1+Test.cs @@ -0,0 +1,17 @@ +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing.Verifiers; +using Microsoft.CodeAnalysis.VisualBasic.Testing; + +namespace Dapr.Jobs.Analyzer.Test +{ + public static partial class VisualBasicAnalyzerVerifier + where TAnalyzer : DiagnosticAnalyzer, new() + { + public class Test : VisualBasicAnalyzerTest + { + public Test() + { + } + } + } +} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1.cs new file mode 100644 index 000000000..d6797eca5 --- /dev/null +++ b/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1.cs @@ -0,0 +1,38 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Testing.Verifiers; +using Microsoft.CodeAnalysis.VisualBasic.Testing; + +namespace Dapr.Jobs.Analyzer.Test +{ + public static partial class VisualBasicAnalyzerVerifier + where TAnalyzer : DiagnosticAnalyzer, new() + { + /// + public static DiagnosticResult Diagnostic() + => VisualBasicAnalyzerVerifier.Diagnostic(); + + /// + public static DiagnosticResult Diagnostic(string diagnosticId) + => VisualBasicAnalyzerVerifier.Diagnostic(diagnosticId); + + /// + public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor) + => VisualBasicAnalyzerVerifier.Diagnostic(descriptor); + + /// + public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected) + { + var test = new Test + { + TestCode = source, + }; + + test.ExpectedDiagnostics.AddRange(expected); + await test.RunAsync(CancellationToken.None); + } + } +} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2+Test.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2+Test.cs new file mode 100644 index 000000000..e74d86b3a --- /dev/null +++ b/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2+Test.cs @@ -0,0 +1,16 @@ +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing.Verifiers; +using Microsoft.CodeAnalysis.VisualBasic.Testing; + +namespace Dapr.Jobs.Analyzer.Test +{ + public static partial class VisualBasicCodeFixVerifier + where TAnalyzer : DiagnosticAnalyzer, new() + where TCodeFix : CodeFixProvider, new() + { + public class Test : VisualBasicCodeFixTest + { + } + } +} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2.cs new file mode 100644 index 000000000..17e3aab75 --- /dev/null +++ b/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2.cs @@ -0,0 +1,61 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CodeFixes; +using Microsoft.CodeAnalysis.Diagnostics; +using Microsoft.CodeAnalysis.Testing; +using Microsoft.CodeAnalysis.Testing.Verifiers; +using Microsoft.CodeAnalysis.VisualBasic.Testing; + +namespace Dapr.Jobs.Analyzer.Test +{ + public static partial class VisualBasicCodeFixVerifier + where TAnalyzer : DiagnosticAnalyzer, new() + where TCodeFix : CodeFixProvider, new() + { + /// + public static DiagnosticResult Diagnostic() + => VisualBasicCodeFixVerifier.Diagnostic(); + + /// + public static DiagnosticResult Diagnostic(string diagnosticId) + => VisualBasicCodeFixVerifier.Diagnostic(diagnosticId); + + /// + public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor) + => VisualBasicCodeFixVerifier.Diagnostic(descriptor); + + /// + public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected) + { + var test = new Test + { + TestCode = source, + }; + + test.ExpectedDiagnostics.AddRange(expected); + await test.RunAsync(CancellationToken.None); + } + + /// + public static async Task VerifyCodeFixAsync(string source, string fixedSource) + => await VerifyCodeFixAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource); + + /// + public static async Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource) + => await VerifyCodeFixAsync(source, new[] { expected }, fixedSource); + + /// + public static async Task VerifyCodeFixAsync(string source, DiagnosticResult[] expected, string fixedSource) + { + var test = new Test + { + TestCode = source, + FixedCode = fixedSource, + }; + + test.ExpectedDiagnostics.AddRange(expected); + await test.RunAsync(CancellationToken.None); + } + } +} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1+Test.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1+Test.cs new file mode 100644 index 000000000..2d9b56550 --- /dev/null +++ b/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1+Test.cs @@ -0,0 +1,14 @@ +using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.Testing.Verifiers; +using Microsoft.CodeAnalysis.VisualBasic.Testing; + +namespace Dapr.Jobs.Analyzer.Test +{ + public static partial class VisualBasicCodeRefactoringVerifier + where TCodeRefactoring : CodeRefactoringProvider, new() + { + public class Test : VisualBasicCodeRefactoringTest + { + } + } +} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1.cs new file mode 100644 index 000000000..e98866ae4 --- /dev/null +++ b/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1.cs @@ -0,0 +1,36 @@ +using System.Threading; +using System.Threading.Tasks; +using Microsoft.CodeAnalysis.CodeRefactorings; +using Microsoft.CodeAnalysis.Testing; + +namespace Dapr.Jobs.Analyzer.Test +{ + public static partial class VisualBasicCodeRefactoringVerifier + where TCodeRefactoring : CodeRefactoringProvider, new() + { + /// + public static async Task VerifyRefactoringAsync(string source, string fixedSource) + { + await VerifyRefactoringAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource); + } + + /// + public static async Task VerifyRefactoringAsync(string source, DiagnosticResult expected, string fixedSource) + { + await VerifyRefactoringAsync(source, new[] { expected }, fixedSource); + } + + /// + public static async Task VerifyRefactoringAsync(string source, DiagnosticResult[] expected, string fixedSource) + { + var test = new Test + { + TestCode = source, + FixedCode = fixedSource, + }; + + test.ExpectedDiagnostics.AddRange(expected); + await test.RunAsync(CancellationToken.None); + } + } +} From 488cf0ce3b52fbf5e40f42ec78a7a52158f5c97f Mon Sep 17 00:00:00 2001 From: Siri Varma Vegiraju Date: Thu, 27 Feb 2025 15:00:09 -0800 Subject: [PATCH 02/10] Remvoe files Signed-off-by: Siri Varma Vegiraju --- src/Dapr.Jobs.Analyzer/Resources.Designer.cs | 106 -------------- src/Dapr.Jobs.Analyzer/Resources.resx | 132 ------------------ .../CSharpAnalyzerVerifier`1+Test.cs | 26 ---- .../Verifiers/CSharpAnalyzerVerifier`1.cs | 38 ----- .../Verifiers/CSharpCodeFixVerifier`2+Test.cs | 28 ---- .../Verifiers/CSharpCodeFixVerifier`2.cs | 61 -------- .../CSharpCodeRefactoringVerifier`1+Test.cs | 26 ---- .../CSharpCodeRefactoringVerifier`1.cs | 36 ----- .../Verifiers/CSharpVerifierHelper.cs | 33 ----- .../VisualBasicAnalyzerVerifier`1+Test.cs | 17 --- .../VisualBasicAnalyzerVerifier`1.cs | 38 ----- .../VisualBasicCodeFixVerifier`2+Test.cs | 16 --- .../Verifiers/VisualBasicCodeFixVerifier`2.cs | 61 -------- ...sualBasicCodeRefactoringVerifier`1+Test.cs | 14 -- .../VisualBasicCodeRefactoringVerifier`1.cs | 36 ----- 15 files changed, 668 deletions(-) delete mode 100644 src/Dapr.Jobs.Analyzer/Resources.Designer.cs delete mode 100644 src/Dapr.Jobs.Analyzer/Resources.resx delete mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1+Test.cs delete mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1.cs delete mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2+Test.cs delete mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2.cs delete mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1+Test.cs delete mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1.cs delete mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpVerifierHelper.cs delete mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1+Test.cs delete mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1.cs delete mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2+Test.cs delete mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2.cs delete mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1+Test.cs delete mode 100644 test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1.cs diff --git a/src/Dapr.Jobs.Analyzer/Resources.Designer.cs b/src/Dapr.Jobs.Analyzer/Resources.Designer.cs deleted file mode 100644 index 47d18d5ab..000000000 --- a/src/Dapr.Jobs.Analyzer/Resources.Designer.cs +++ /dev/null @@ -1,106 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.0 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace Dapr.Jobs.Analyzer -{ - using System; - using System.Reflection; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources - { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() - { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager - { - get - { - if (object.ReferenceEquals(resourceMan, null)) - { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Dapr.Jobs.Analyzer.Resources", typeof(Resources).GetTypeInfo().Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture - { - get - { - return resourceCulture; - } - set - { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to Type names should be all uppercase.. - /// - internal static string AnalyzerDescription - { - get - { - return ResourceManager.GetString("AnalyzerDescription", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Type name '{0}' contains lowercase letters. - /// - internal static string AnalyzerMessageFormat - { - get - { - return ResourceManager.GetString("AnalyzerMessageFormat", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Type name contains lowercase letters. - /// - internal static string AnalyzerTitle - { - get - { - return ResourceManager.GetString("AnalyzerTitle", resourceCulture); - } - } - } -} diff --git a/src/Dapr.Jobs.Analyzer/Resources.resx b/src/Dapr.Jobs.Analyzer/Resources.resx deleted file mode 100644 index 410edccd7..000000000 --- a/src/Dapr.Jobs.Analyzer/Resources.resx +++ /dev/null @@ -1,132 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 2.0 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - Type names should be all uppercase. - An optional longer localizable description of the diagnostic. - - - Type name '{0}' contains lowercase letters - The format-able message the diagnostic displays. - - - Type name contains lowercase letters - The title of the diagnostic. - - \ No newline at end of file diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1+Test.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1+Test.cs deleted file mode 100644 index 7a79e589c..000000000 --- a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1+Test.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Microsoft.CodeAnalysis.CSharp.Testing; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Testing.Verifiers; - -namespace Dapr.Jobs.Analyzer.Test -{ - public static partial class CSharpAnalyzerVerifier - where TAnalyzer : DiagnosticAnalyzer, new() - { - public class Test : CSharpAnalyzerTest - { - public Test() - { - SolutionTransforms.Add((solution, projectId) => - { - var compilationOptions = solution.GetProject(projectId).CompilationOptions; - compilationOptions = compilationOptions.WithSpecificDiagnosticOptions( - compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings)); - solution = solution.WithProjectCompilationOptions(projectId, compilationOptions); - - return solution; - }); - } - } - } -} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1.cs deleted file mode 100644 index 4fcf72386..000000000 --- a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpAnalyzerVerifier`1.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp.Testing; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Testing; -using Microsoft.CodeAnalysis.Testing.Verifiers; - -namespace Dapr.Jobs.Analyzer.Test -{ - public static partial class CSharpAnalyzerVerifier - where TAnalyzer : DiagnosticAnalyzer, new() - { - /// - public static DiagnosticResult Diagnostic() - => CSharpAnalyzerVerifier.Diagnostic(); - - /// - public static DiagnosticResult Diagnostic(string diagnosticId) - => CSharpAnalyzerVerifier.Diagnostic(diagnosticId); - - /// - public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor) - => CSharpAnalyzerVerifier.Diagnostic(descriptor); - - /// - public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected) - { - var test = new Test - { - TestCode = source, - }; - - test.ExpectedDiagnostics.AddRange(expected); - await test.RunAsync(CancellationToken.None); - } - } -} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2+Test.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2+Test.cs deleted file mode 100644 index c0a98b754..000000000 --- a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2+Test.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CSharp.Testing; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Testing.Verifiers; - -namespace Dapr.Jobs.Analyzer.Test -{ - public static partial class CSharpCodeFixVerifier - where TAnalyzer : DiagnosticAnalyzer, new() - where TCodeFix : CodeFixProvider, new() - { - public class Test : CSharpCodeFixTest - { - public Test() - { - SolutionTransforms.Add((solution, projectId) => - { - var compilationOptions = solution.GetProject(projectId).CompilationOptions; - compilationOptions = compilationOptions.WithSpecificDiagnosticOptions( - compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings)); - solution = solution.WithProjectCompilationOptions(projectId, compilationOptions); - - return solution; - }); - } - } - } -} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2.cs deleted file mode 100644 index 4bb1e0b4f..000000000 --- a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeFixVerifier`2.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.CSharp.Testing; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Testing; -using Microsoft.CodeAnalysis.Testing.Verifiers; - -namespace Dapr.Jobs.Analyzer.Test -{ - public static partial class CSharpCodeFixVerifier - where TAnalyzer : DiagnosticAnalyzer, new() - where TCodeFix : CodeFixProvider, new() - { - /// - public static DiagnosticResult Diagnostic() - => CSharpCodeFixVerifier.Diagnostic(); - - /// - public static DiagnosticResult Diagnostic(string diagnosticId) - => CSharpCodeFixVerifier.Diagnostic(diagnosticId); - - /// - public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor) - => CSharpCodeFixVerifier.Diagnostic(descriptor); - - /// - public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected) - { - var test = new Test - { - TestCode = source, - }; - - test.ExpectedDiagnostics.AddRange(expected); - await test.RunAsync(CancellationToken.None); - } - - /// - public static async Task VerifyCodeFixAsync(string source, string fixedSource) - => await VerifyCodeFixAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource); - - /// - public static async Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource) - => await VerifyCodeFixAsync(source, new[] { expected }, fixedSource); - - /// - public static async Task VerifyCodeFixAsync(string source, DiagnosticResult[] expected, string fixedSource) - { - var test = new Test - { - TestCode = source, - FixedCode = fixedSource, - }; - - test.ExpectedDiagnostics.AddRange(expected); - await test.RunAsync(CancellationToken.None); - } - } -} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1+Test.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1+Test.cs deleted file mode 100644 index 25b37ff6c..000000000 --- a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1+Test.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.CSharp.Testing; -using Microsoft.CodeAnalysis.Testing.Verifiers; - -namespace Dapr.Jobs.Analyzer.Test -{ - public static partial class CSharpCodeRefactoringVerifier - where TCodeRefactoring : CodeRefactoringProvider, new() - { - public class Test : CSharpCodeRefactoringTest - { - public Test() - { - SolutionTransforms.Add((solution, projectId) => - { - var compilationOptions = solution.GetProject(projectId).CompilationOptions; - compilationOptions = compilationOptions.WithSpecificDiagnosticOptions( - compilationOptions.SpecificDiagnosticOptions.SetItems(CSharpVerifierHelper.NullableWarnings)); - solution = solution.WithProjectCompilationOptions(projectId, compilationOptions); - - return solution; - }); - } - } - } -} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1.cs deleted file mode 100644 index 705f691eb..000000000 --- a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpCodeRefactoringVerifier`1.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.Testing; - -namespace Dapr.Jobs.Analyzer.Test -{ - public static partial class CSharpCodeRefactoringVerifier - where TCodeRefactoring : CodeRefactoringProvider, new() - { - /// - public static async Task VerifyRefactoringAsync(string source, string fixedSource) - { - await VerifyRefactoringAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource); - } - - /// - public static async Task VerifyRefactoringAsync(string source, DiagnosticResult expected, string fixedSource) - { - await VerifyRefactoringAsync(source, new[] { expected }, fixedSource); - } - - /// - public static async Task VerifyRefactoringAsync(string source, DiagnosticResult[] expected, string fixedSource) - { - var test = new Test - { - TestCode = source, - FixedCode = fixedSource, - }; - - test.ExpectedDiagnostics.AddRange(expected); - await test.RunAsync(CancellationToken.None); - } - } -} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpVerifierHelper.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpVerifierHelper.cs deleted file mode 100644 index d9875afe8..000000000 --- a/test/Dapr.Jobs.Analyzer.Test/Verifiers/CSharpVerifierHelper.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Immutable; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; - -namespace Dapr.Jobs.Analyzer.Test -{ - internal static class CSharpVerifierHelper - { - /// - /// By default, the compiler reports diagnostics for nullable reference types at - /// , and the analyzer test framework defaults to only validating - /// diagnostics at . This map contains all compiler diagnostic IDs - /// related to nullability mapped to , which is then used to enable all - /// of these warnings for default validation during analyzer and code fix tests. - /// - internal static ImmutableDictionary NullableWarnings { get; } = GetNullableWarningsFromCompiler(); - - private static ImmutableDictionary GetNullableWarningsFromCompiler() - { - string[] args = { "/warnaserror:nullable" }; - var commandLineArguments = CSharpCommandLineParser.Default.Parse(args, baseDirectory: Environment.CurrentDirectory, sdkDirectory: Environment.CurrentDirectory); - var nullableWarnings = commandLineArguments.CompilationOptions.SpecificDiagnosticOptions; - - // Workaround for https://github.com/dotnet/roslyn/issues/41610 - nullableWarnings = nullableWarnings - .SetItem("CS8632", ReportDiagnostic.Error) - .SetItem("CS8669", ReportDiagnostic.Error); - - return nullableWarnings; - } - } -} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1+Test.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1+Test.cs deleted file mode 100644 index 25cc5ab7c..000000000 --- a/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1+Test.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Testing.Verifiers; -using Microsoft.CodeAnalysis.VisualBasic.Testing; - -namespace Dapr.Jobs.Analyzer.Test -{ - public static partial class VisualBasicAnalyzerVerifier - where TAnalyzer : DiagnosticAnalyzer, new() - { - public class Test : VisualBasicAnalyzerTest - { - public Test() - { - } - } - } -} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1.cs deleted file mode 100644 index d6797eca5..000000000 --- a/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicAnalyzerVerifier`1.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Testing; -using Microsoft.CodeAnalysis.Testing.Verifiers; -using Microsoft.CodeAnalysis.VisualBasic.Testing; - -namespace Dapr.Jobs.Analyzer.Test -{ - public static partial class VisualBasicAnalyzerVerifier - where TAnalyzer : DiagnosticAnalyzer, new() - { - /// - public static DiagnosticResult Diagnostic() - => VisualBasicAnalyzerVerifier.Diagnostic(); - - /// - public static DiagnosticResult Diagnostic(string diagnosticId) - => VisualBasicAnalyzerVerifier.Diagnostic(diagnosticId); - - /// - public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor) - => VisualBasicAnalyzerVerifier.Diagnostic(descriptor); - - /// - public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected) - { - var test = new Test - { - TestCode = source, - }; - - test.ExpectedDiagnostics.AddRange(expected); - await test.RunAsync(CancellationToken.None); - } - } -} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2+Test.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2+Test.cs deleted file mode 100644 index e74d86b3a..000000000 --- a/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2+Test.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Testing.Verifiers; -using Microsoft.CodeAnalysis.VisualBasic.Testing; - -namespace Dapr.Jobs.Analyzer.Test -{ - public static partial class VisualBasicCodeFixVerifier - where TAnalyzer : DiagnosticAnalyzer, new() - where TCodeFix : CodeFixProvider, new() - { - public class Test : VisualBasicCodeFixTest - { - } - } -} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2.cs deleted file mode 100644 index 17e3aab75..000000000 --- a/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeFixVerifier`2.cs +++ /dev/null @@ -1,61 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CodeFixes; -using Microsoft.CodeAnalysis.Diagnostics; -using Microsoft.CodeAnalysis.Testing; -using Microsoft.CodeAnalysis.Testing.Verifiers; -using Microsoft.CodeAnalysis.VisualBasic.Testing; - -namespace Dapr.Jobs.Analyzer.Test -{ - public static partial class VisualBasicCodeFixVerifier - where TAnalyzer : DiagnosticAnalyzer, new() - where TCodeFix : CodeFixProvider, new() - { - /// - public static DiagnosticResult Diagnostic() - => VisualBasicCodeFixVerifier.Diagnostic(); - - /// - public static DiagnosticResult Diagnostic(string diagnosticId) - => VisualBasicCodeFixVerifier.Diagnostic(diagnosticId); - - /// - public static DiagnosticResult Diagnostic(DiagnosticDescriptor descriptor) - => VisualBasicCodeFixVerifier.Diagnostic(descriptor); - - /// - public static async Task VerifyAnalyzerAsync(string source, params DiagnosticResult[] expected) - { - var test = new Test - { - TestCode = source, - }; - - test.ExpectedDiagnostics.AddRange(expected); - await test.RunAsync(CancellationToken.None); - } - - /// - public static async Task VerifyCodeFixAsync(string source, string fixedSource) - => await VerifyCodeFixAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource); - - /// - public static async Task VerifyCodeFixAsync(string source, DiagnosticResult expected, string fixedSource) - => await VerifyCodeFixAsync(source, new[] { expected }, fixedSource); - - /// - public static async Task VerifyCodeFixAsync(string source, DiagnosticResult[] expected, string fixedSource) - { - var test = new Test - { - TestCode = source, - FixedCode = fixedSource, - }; - - test.ExpectedDiagnostics.AddRange(expected); - await test.RunAsync(CancellationToken.None); - } - } -} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1+Test.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1+Test.cs deleted file mode 100644 index 2d9b56550..000000000 --- a/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1+Test.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.Testing.Verifiers; -using Microsoft.CodeAnalysis.VisualBasic.Testing; - -namespace Dapr.Jobs.Analyzer.Test -{ - public static partial class VisualBasicCodeRefactoringVerifier - where TCodeRefactoring : CodeRefactoringProvider, new() - { - public class Test : VisualBasicCodeRefactoringTest - { - } - } -} diff --git a/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1.cs b/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1.cs deleted file mode 100644 index e98866ae4..000000000 --- a/test/Dapr.Jobs.Analyzer.Test/Verifiers/VisualBasicCodeRefactoringVerifier`1.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Microsoft.CodeAnalysis.CodeRefactorings; -using Microsoft.CodeAnalysis.Testing; - -namespace Dapr.Jobs.Analyzer.Test -{ - public static partial class VisualBasicCodeRefactoringVerifier - where TCodeRefactoring : CodeRefactoringProvider, new() - { - /// - public static async Task VerifyRefactoringAsync(string source, string fixedSource) - { - await VerifyRefactoringAsync(source, DiagnosticResult.EmptyDiagnosticResults, fixedSource); - } - - /// - public static async Task VerifyRefactoringAsync(string source, DiagnosticResult expected, string fixedSource) - { - await VerifyRefactoringAsync(source, new[] { expected }, fixedSource); - } - - /// - public static async Task VerifyRefactoringAsync(string source, DiagnosticResult[] expected, string fixedSource) - { - var test = new Test - { - TestCode = source, - FixedCode = fixedSource, - }; - - test.ExpectedDiagnostics.AddRange(expected); - await test.RunAsync(CancellationToken.None); - } - } -} From 674cda474cb646f5ad805c681421160c6168741d Mon Sep 17 00:00:00 2001 From: Siri Varma Vegiraju Date: Thu, 27 Feb 2025 15:31:38 -0800 Subject: [PATCH 03/10] Fix deps Signed-off-by: Siri Varma Vegiraju --- .../Dapr.Jobs.Analyzer.csproj | 18 ++---- .../Dapr.Jobs.Analyzer.Test.csproj | 3 +- .../DaprJobsAnalyzerUnitTests.cs | 59 ------------------- 3 files changed, 6 insertions(+), 74 deletions(-) delete mode 100644 test/Dapr.Jobs.Analyzer.Test/DaprJobsAnalyzerUnitTests.cs diff --git a/src/Dapr.Jobs.Analyzer/Dapr.Jobs.Analyzer.csproj b/src/Dapr.Jobs.Analyzer/Dapr.Jobs.Analyzer.csproj index 647fe7b51..78e89d0a1 100644 --- a/src/Dapr.Jobs.Analyzer/Dapr.Jobs.Analyzer.csproj +++ b/src/Dapr.Jobs.Analyzer/Dapr.Jobs.Analyzer.csproj @@ -2,13 +2,13 @@ netstandard2.0 + false - - - *$(MSBuildProjectFile)* + enable + enable true - + @@ -20,16 +20,8 @@ false - - false - - This package contains Roslyn analyzers for actors. + This package contains Roslyn analyzers for jobs. $(PackageTags) - - - - - diff --git a/test/Dapr.Jobs.Analyzer.Test/Dapr.Jobs.Analyzer.Test.csproj b/test/Dapr.Jobs.Analyzer.Test/Dapr.Jobs.Analyzer.Test.csproj index 838577171..5d64125cb 100644 --- a/test/Dapr.Jobs.Analyzer.Test/Dapr.Jobs.Analyzer.Test.csproj +++ b/test/Dapr.Jobs.Analyzer.Test/Dapr.Jobs.Analyzer.Test.csproj @@ -1,13 +1,12 @@ - netcoreapp3.1 enable enable false true - + diff --git a/test/Dapr.Jobs.Analyzer.Test/DaprJobsAnalyzerUnitTests.cs b/test/Dapr.Jobs.Analyzer.Test/DaprJobsAnalyzerUnitTests.cs deleted file mode 100644 index 1927755ed..000000000 --- a/test/Dapr.Jobs.Analyzer.Test/DaprJobsAnalyzerUnitTests.cs +++ /dev/null @@ -1,59 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System.Threading.Tasks; -using VerifyCS = Dapr.Jobs.Analyzer.Test.CSharpCodeFixVerifier< - Dapr.Jobs.Analyzer.DaprJobsAnalyzerAnalyzer, - Dapr.Jobs.Analyzer.DaprJobsAnalyzerCodeFixProvider>; - -namespace Dapr.Jobs.Analyzer.Test -{ - [TestClass] - public class DaprJobsAnalyzerUnitTest - { - //No diagnostics expected to show up - [TestMethod] - public async Task TestMethod1() - { - var test = @""; - - await VerifyCS.VerifyAnalyzerAsync(test); - } - - //Diagnostic and CodeFix both triggered and checked for - [TestMethod] - public async Task TestMethod2() - { - var test = @" - using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; - using System.Threading.Tasks; - using System.Diagnostics; - - namespace ConsoleApplication1 - { - class {|#0:TypeName|} - { - } - }"; - - var fixtest = @" - using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; - using System.Threading.Tasks; - using System.Diagnostics; - - namespace ConsoleApplication1 - { - class TYPENAME - { - } - }"; - - var expected = VerifyCS.Diagnostic("DaprJobsAnalyzer").WithLocation(0).WithArguments("TypeName"); - await VerifyCS.VerifyCodeFixAsync(test, expected, fixtest); - } - } -} From 2a8a0258c27341c59419446d336127d8fe7b78d0 Mon Sep 17 00:00:00 2001 From: Siri Varma Vegiraju Date: Fri, 28 Feb 2025 14:01:35 -0800 Subject: [PATCH 04/10] Add tests Signed-off-by: Siri Varma Vegiraju --- all.sln | 8 - .../Properties/launchSettings.json | 12 + .../Properties/launchSettings.json | 12 + examples/Jobs/JobsSample/Program.cs | 2 +- .../DaprJobsAnalyzerAnalyzer.cs | 59 ++- .../Dapr.Jobs.Analyzer.Test.csproj | 1 + .../DaprJobAnalyzerTest.cs | 420 ++++++++++++++++++ 7 files changed, 491 insertions(+), 23 deletions(-) create mode 100644 examples/AI/ConversationalAI/Properties/launchSettings.json create mode 100644 examples/Client/PublishSubscribe/StreamingSubscriptionExample/Properties/launchSettings.json create mode 100644 test/Dapr.Jobs.Analyzer.Test/DaprJobAnalyzerTest.cs diff --git a/all.sln b/all.sln index dfed8c941..57d0b4513 100644 --- a/all.sln +++ b/all.sln @@ -159,8 +159,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Jobs.Analyzer", "src\D EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Jobs.Analyzer.Test", "test\Dapr.Jobs.Analyzer.Test\Dapr.Jobs.Analyzer.Test.csproj", "{CADEAE45-8981-4723-B641-9C28251C7D3B}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Jobs.Analyzer.Vsix", "src\Dapr.Jobs.Analyzer\Dapr.Jobs.Analyzer.Vsix\Dapr.Jobs.Analyzer.Vsix.csproj", "{0C3D3AE2-8A32-4683-992B-5FC37C4B644D}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -417,16 +415,11 @@ Global {CADEAE45-8981-4723-B641-9C28251C7D3B}.Debug|Any CPU.Build.0 = Debug|Any CPU {CADEAE45-8981-4723-B641-9C28251C7D3B}.Release|Any CPU.ActiveCfg = Release|Any CPU {CADEAE45-8981-4723-B641-9C28251C7D3B}.Release|Any CPU.Build.0 = Release|Any CPU - {0C3D3AE2-8A32-4683-992B-5FC37C4B644D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0C3D3AE2-8A32-4683-992B-5FC37C4B644D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0C3D3AE2-8A32-4683-992B-5FC37C4B644D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0C3D3AE2-8A32-4683-992B-5FC37C4B644D}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {C2DB4B64-B7C3-4FED-8753-C040F677C69A} = {27C5D71D-0721-4221-9286-B94AB07B58CF} {41BF4392-54BD-4FE7-A3EB-CD045F88CA9A} = {DD020B34-460F-455F-8D17-CF4A949F100B} {B9C12532-0969-4DAC-A2F8-CA9208D7A901} = {27C5D71D-0721-4221-9286-B94AB07B58CF} {62E41317-ED5D-4AA4-B129-C9E56C27354C} = {27C5D71D-0721-4221-9286-B94AB07B58CF} @@ -497,7 +490,6 @@ Global {E90114C6-86FC-43B8-AE5C-D9273CF21FE4} = {DD020B34-460F-455F-8D17-CF4A949F100B} {28B87C37-4B52-400F-B84D-64F134931BDC} = {27C5D71D-0721-4221-9286-B94AB07B58CF} {CADEAE45-8981-4723-B641-9C28251C7D3B} = {DD020B34-460F-455F-8D17-CF4A949F100B} - {0C3D3AE2-8A32-4683-992B-5FC37C4B644D} = {27C5D71D-0721-4221-9286-B94AB07B58CF} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {65220BF2-EAE1-4CB2-AA58-EBE80768CB40} diff --git a/examples/AI/ConversationalAI/Properties/launchSettings.json b/examples/AI/ConversationalAI/Properties/launchSettings.json new file mode 100644 index 000000000..bb6222129 --- /dev/null +++ b/examples/AI/ConversationalAI/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "ConversationalAI": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:56624;http://localhost:56625" + } + } +} \ No newline at end of file diff --git a/examples/Client/PublishSubscribe/StreamingSubscriptionExample/Properties/launchSettings.json b/examples/Client/PublishSubscribe/StreamingSubscriptionExample/Properties/launchSettings.json new file mode 100644 index 000000000..afe549903 --- /dev/null +++ b/examples/Client/PublishSubscribe/StreamingSubscriptionExample/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "profiles": { + "StreamingSubscriptionExample": { + "commandName": "Project", + "launchBrowser": true, + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development" + }, + "applicationUrl": "https://localhost:56622;http://localhost:56623" + } + } +} \ No newline at end of file diff --git a/examples/Jobs/JobsSample/Program.cs b/examples/Jobs/JobsSample/Program.cs index f19e375b3..ed1e71528 100644 --- a/examples/Jobs/JobsSample/Program.cs +++ b/examples/Jobs/JobsSample/Program.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ // Copyright 2024 The Dapr Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/src/Dapr.Jobs.Analyzer/DaprJobsAnalyzerAnalyzer.cs b/src/Dapr.Jobs.Analyzer/DaprJobsAnalyzerAnalyzer.cs index e5e36964f..2bf51d4df 100644 --- a/src/Dapr.Jobs.Analyzer/DaprJobsAnalyzerAnalyzer.cs +++ b/src/Dapr.Jobs.Analyzer/DaprJobsAnalyzerAnalyzer.cs @@ -22,6 +22,12 @@ public class DaprJobsAnalyzerAnalyzer : DiagnosticAnalyzer isEnabledByDefault: true ); + private static readonly string DaprJobsNameSpace = "Dapr.Jobs"; + private static readonly string DaprJobScheduleJobAsyncMethod = "ScheduleJobAsync"; + private static readonly string EndpointNameSpace = "Microsoft.AspNetCore.Builder"; + private static readonly string MapPostMethod = "MapPost"; + private static readonly string DaprJobInvocatoinUrlResource = "job"; + /// public override ImmutableArray SupportedDiagnostics { get { return ImmutableArray.Create(DaprJobHandlerRule); } } @@ -38,11 +44,15 @@ private static void AnalyzeJobSchedulerHandler(SyntaxNodeAnalysisContext context { var invocationExpression = (InvocationExpressionSyntax)context.Node; - var memberAccess = invocationExpression.Expression as MemberAccessExpressionSyntax; - if (memberAccess?.Name.ToString() == "ScheduleJobAsync") + if (invocationExpression.Expression is not MemberAccessExpressionSyntax memberAccess) + { + return; + } + + if (IsNamespaceAndMethodNameEqual(context, invocationExpression, DaprJobsNameSpace, DaprJobScheduleJobAsyncMethod)) { var arguments = invocationExpression.ArgumentList.Arguments; - if (arguments.Count == 1 && arguments[0].Expression is LiteralExpressionSyntax literal) + if (arguments.Count > 0 && arguments[0].Expression is LiteralExpressionSyntax literal) { string jobName = literal.Token.ValueText; @@ -59,29 +69,50 @@ private static void CheckForEndpointRoute(SyntaxNodeAnalysisContext context, str // Search for MapPost with the corresponding route var endpointMappings = root.DescendantNodes() .OfType() - .Where(invocation => invocation.Expression.ToString().Contains("MapPost")) + .Where(invocation => IsNamespaceAndMethodNameEqual(context, invocation, EndpointNameSpace, MapPostMethod)) .ToList(); foreach (var mapping in endpointMappings) { // Look for route patterns like "/job/{jobname}" - var argument = mapping.ArgumentList.Arguments.FirstOrDefault()?.ToString(); + var argumentExpression = mapping.ArgumentList.Arguments.FirstOrDefault()?.Expression; + string argument = string.Empty; + if (argumentExpression is LiteralExpressionSyntax literal) + { + argument = literal.Token.ValueText; // This extracts the string without quotes + } - if (argument != null) + // route patterns like "/job/{jobname} or /job/myJob" + string[] endpointSplit = argument.Split('/'); + if (endpointSplit.Length == 3 + && endpointSplit[1].Equals(DaprJobInvocatoinUrlResource) + && (endpointSplit[2].Equals(jobName) || ((endpointSplit[2].StartsWith("{") && endpointSplit[2].EndsWith("}"))))) { - string[] endpointSplit = argument.Split('/'); - if (endpointSplit.Length == 3 - && endpointSplit[1].Equals("job") - && (endpointSplit[2].Equals(jobName) || ((endpointSplit[2].StartsWith("{") && endpointSplit[2].EndsWith("}"))))) - { - return; - } + return; } } // If no matching route was found, report a diagnostic - var diagnostic = Diagnostic.Create(DaprJobHandlerRule, context.Node.GetLocation(), jobName); + var diagnostic = Diagnostic.Create(DaprJobHandlerRule, default, jobName); context.ReportDiagnostic(diagnostic); } + + private static bool IsNamespaceAndMethodNameEqual(SyntaxNodeAnalysisContext context, InvocationExpressionSyntax invocation, string symbolNamespace, string methodName) + { + var symbolInfo = context.SemanticModel.GetSymbolInfo(invocation.Expression); + if (symbolInfo.Symbol is not IMethodSymbol methodSymbol) + { + return false; + } + + // Check if the receiver is of type DaprJobsClient + if (methodSymbol?.Name == methodName && + methodSymbol.ContainingNamespace.ToDisplayString() == symbolNamespace) + { + return true; + } + + return false; + } } } diff --git a/test/Dapr.Jobs.Analyzer.Test/Dapr.Jobs.Analyzer.Test.csproj b/test/Dapr.Jobs.Analyzer.Test/Dapr.Jobs.Analyzer.Test.csproj index 5d64125cb..53f52d98b 100644 --- a/test/Dapr.Jobs.Analyzer.Test/Dapr.Jobs.Analyzer.Test.csproj +++ b/test/Dapr.Jobs.Analyzer.Test/Dapr.Jobs.Analyzer.Test.csproj @@ -24,6 +24,7 @@ + diff --git a/test/Dapr.Jobs.Analyzer.Test/DaprJobAnalyzerTest.cs b/test/Dapr.Jobs.Analyzer.Test/DaprJobAnalyzerTest.cs new file mode 100644 index 000000000..22509f07e --- /dev/null +++ b/test/Dapr.Jobs.Analyzer.Test/DaprJobAnalyzerTest.cs @@ -0,0 +1,420 @@ +namespace Dapr.Jobs.Analyzer.Tests +{ + using Microsoft.CodeAnalysis.CSharp.Testing; + using Microsoft.CodeAnalysis.Testing; + using Microsoft.CodeAnalysis; + using Microsoft.AspNetCore.Builder; + using Dapr.Jobs.Models; + using System.Text; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.Extensions.Hosting; + + public class DaprJobsAnalyzerAnalyzerTests + { + +#if NET6_0 + private static readonly ReferenceAssemblies referenceAssemblies = ReferenceAssemblies.Net.Net60; +#elif NET7_0 + private static readonly ReferenceAssemblies referenceAssemblies = ReferenceAssemblies.Net.Net70; +#elif NET8_0 + private static readonly ReferenceAssemblies referenceAssemblies = ReferenceAssemblies.Net.Net80; +#elif NET9_0 + private static readonly ReferenceAssemblies referenceAssemblies = ReferenceAssemblies.Net.Net90; +#endif + + private static readonly DiagnosticDescriptor DaprJobHandlerRule = new DiagnosticDescriptor( +#pragma warning disable RS2008 // Enable analyzer release tracking + id: "DAPRJOBS0001", +#pragma warning restore RS2008 // Enable analyzer release tracking + title: "Ensure Post Mapper handler is present for all the Scheduled Jobs", + messageFormat: "There should be a mapping post endpoint for each scheduled job to make sure app receives notifications for all the scheduled jobs", + category: "Usage", + DiagnosticSeverity.Warning, + isEnabledByDefault: true + ); + + [Fact] + public async Task AnalyzeJobSchedulerHandler_ShouldRaiseDiagnostic_WhenJobHasNoEndpointMapping() + { + var testCode = @" + using System; + using System.Text; + using System.Threading.Tasks; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.AspNetCore.Builder; + using Dapr.Jobs; + using Dapr.Jobs.Extensions; + using Dapr.Jobs.Models; + + public static class Program + { + public static void Main() + { + var builder = WebApplication.CreateBuilder(); + builder.Services.AddDaprJobsClient(); + var app = builder.Build(); + using var scope = app.Services.CreateScope(); + + var daprJobsClient = scope.ServiceProvider.GetRequiredService(); + + daprJobsClient.ScheduleJobAsync(""myJob"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), + Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); + } + }"; + + var expectedDiagnostic = new DiagnosticResult(DaprJobHandlerRule); + + await VerifyAnalyzerAsync(testCode, expectedDiagnostic); + } + + [Fact] + public async Task AnalyzeJobSchedulerHandler_ShouldRaiseDiagnostic_WhenJobHasHasEndpointButDoesNotMapToJobName() + { + var testCode = @" + using System; + using System.Text; + using System.Threading.Tasks; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.AspNetCore.Builder; + using Dapr.Jobs; + using Dapr.Jobs.Extensions; + using Dapr.Jobs.Models; + + public static class Program + { + public static void Main() + { + var builder = WebApplication.CreateBuilder(); + builder.Services.AddDaprJobsClient(); + var app = builder.Build(); + using var scope = app.Services.CreateScope(); + + var daprJobsClient = scope.ServiceProvider.GetRequiredService(); + + daprJobsClient.ScheduleJobAsync(""myJob"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), + Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); + + app.UseEndpoints(endpoints => + { + endpoints.MapPost(""/job/JobA"", async context => + { + }); + }); + } + }"; + + var expectedDiagnostic = new DiagnosticResult(DaprJobHandlerRule); + + await VerifyAnalyzerAsync(testCode, expectedDiagnostic); + } + + [Fact] + public async Task AnalyzeJobSchedulerHandler_ShouldNotRaiseDiagnostic_WhenScheduleJobIsNotCalled() + { + var testCode = @" + using System; + using System.Text; + using System.Threading.Tasks; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.AspNetCore.Builder; + using Dapr.Jobs; + using Dapr.Jobs.Extensions; + using Dapr.Jobs.Models; + + public static class Program + { + public static void Main() + { + var builder = WebApplication.CreateBuilder(); + builder.Services.AddDaprJobsClient(); + var app = builder.Build(); + using var scope = app.Services.CreateScope(); + + var daprJobsClient = scope.ServiceProvider.GetRequiredService(); + + app.UseEndpoints(endpoints => + { + endpoints.MapPost(""/job/JobA"", async context => + { + }); + }); + } + }"; + + var expectedDiagnostic = new DiagnosticResult(DaprJobHandlerRule); + + await VerifyAnalyzerAsync(testCode); + } + + [Fact] + public async Task AnalyzeJobSchedulerHandler_ShouldRaiseDiagnostic_ForEachInstanceOfScheduledJobsDontHaveMappings() + { + var testCode = @" + using System; + using System.Text; + using System.Threading.Tasks; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.AspNetCore.Builder; + using Dapr.Jobs; + using Dapr.Jobs.Extensions; + using Dapr.Jobs.Models; + + public static class Program + { + public static void Main() + { + var builder = WebApplication.CreateBuilder(); + builder.Services.AddDaprJobsClient(); + var app = builder.Build(); + using var scope = app.Services.CreateScope(); + + var daprJobsClient = scope.ServiceProvider.GetRequiredService(); + + daprJobsClient.ScheduleJobAsync(""myJob"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), + Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); + daprJobsClient.ScheduleJobAsync(""myJob2"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), + Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); + } + }"; + + var expectedDiagnostic = new DiagnosticResult(DaprJobHandlerRule); + + await VerifyAnalyzerAsync(testCode, expectedDiagnostic, expectedDiagnostic); + } + + [Fact] + public async Task AnalyzeJobSchedulerHandler_ShouldRaiseDiagnostic_OnlyOnceWhenOneJobHasMappingAndOtherDoesNot() + { + var testCode = @" + using System; + using System.Text; + using System.Threading.Tasks; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.AspNetCore.Builder; + using Dapr.Jobs; + using Dapr.Jobs.Extensions; + using Dapr.Jobs.Models; + + public static class Program + { + public static void Main() + { + var builder = WebApplication.CreateBuilder(); + builder.Services.AddDaprJobsClient(); + var app = builder.Build(); + using var scope = app.Services.CreateScope(); + + var daprJobsClient = scope.ServiceProvider.GetRequiredService(); + + daprJobsClient.ScheduleJobAsync(""myJob"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), + Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); + daprJobsClient.ScheduleJobAsync(""myJob2"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), + Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); + + app.UseEndpoints(endpoints => + { + endpoints.MapPost(""/job/myJob"", async context => + { + }); + }); + } + }"; + + var expectedDiagnostic = new DiagnosticResult(DaprJobHandlerRule); + + await VerifyAnalyzerAsync(testCode, expectedDiagnostic); + } + + [Fact] + public async Task AnalyzeJobSchedulerHandler_ShouldNotRaiseDiagnostic_WhenTheMappingExistsAsAParameter() + { + var testCode = @" + using System; + using System.Text; + using System.Threading.Tasks; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.AspNetCore.Builder; + using Dapr.Jobs; + using Dapr.Jobs.Extensions; + using Dapr.Jobs.Models; + + public static class Program + { + public static void Main() + { + var builder = WebApplication.CreateBuilder(); + builder.Services.AddDaprJobsClient(); + var app = builder.Build(); + using var scope = app.Services.CreateScope(); + + var daprJobsClient = scope.ServiceProvider.GetRequiredService(); + + daprJobsClient.ScheduleJobAsync(""myJob"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), + Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); + daprJobsClient.ScheduleJobAsync(""myJob1"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), + Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); + daprJobsClient.ScheduleJobAsync(""myJob2"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), + Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); + + app.UseEndpoints(endpoints => + { + endpoints.MapPost(""/job/{myJob}"", async context => + { + }); + }); + } + }"; + + await VerifyAnalyzerAsync(testCode); + } + + + [Fact] + public async Task AnalyzeJobSchedulerHandler_ShouldNotRaiseDiagnostic_WhenJobHasEndpointMapping() + { + var testCode = @" + using System; + using System.Text; + using System.Threading.Tasks; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.AspNetCore.Builder; + using Dapr.Jobs; + using Dapr.Jobs.Extensions; + using Dapr.Jobs.Models; + + public static class Program + { + public static void Main() + { + var builder = WebApplication.CreateBuilder(); + builder.Services.AddDaprJobsClient(); + var app = builder.Build(); + using var scope = app.Services.CreateScope(); + + var daprJobsClient = scope.ServiceProvider.GetRequiredService(); + + daprJobsClient.ScheduleJobAsync(""myJob"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), + Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); + daprJobsClient.ScheduleJobAsync(""myJob2"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), + Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); + + app.UseEndpoints(endpoints => + { + endpoints.MapPost(""/job/myJob"", async context => + { + }); + endpoints.MapPost(""/job/myJob2"", async context => + { + }); + }); + } + }"; + + await VerifyAnalyzerAsync(testCode); + } + + [Fact] + public async Task AnalyzeJobSchedulerHandler_ShouldNotRaiseDiagnostic_WhenJobHasEndpointMappingIrrespectiveOfNumberOfMethodCallsOnScheduleJob() + { + var testCode = @" + using System; + using System.Text; + using System.Threading.Tasks; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.AspNetCore.Builder; + using Dapr.Jobs; + using Dapr.Jobs.Extensions; + using Dapr.Jobs.Models; + + public static class Program + { + public static async Task Main() + { + var builder = WebApplication.CreateBuilder(); + builder.Services.AddDaprJobsClient(); + var app = builder.Build(); + using var scope = app.Services.CreateScope(); + + var daprJobsClient = scope.ServiceProvider.GetRequiredService(); + + daprJobsClient.ScheduleJobAsync(""myJob"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), + Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); + await daprJobsClient.ScheduleJobAsync(""myJob2"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), + Encoding.UTF8.GetBytes(""This is a test""), repeats: 10); + + app.UseEndpoints(endpoints => + { + endpoints.MapPost(""/job/myJob"", async context => + { + }); + endpoints.MapPost(""/job/myJob2"", async context => + { + }); + }); + } + }"; + + await VerifyAnalyzerAsync(testCode); + } + + [Fact] + public async Task AnalyzeJobSchedulerHandler_ShouldNotRaiseDiagnostic_WhenScheduleJobDoesNotBelongToDaprJobClient() + { + var testCode = @" + using System; + using System.Text; + using System.Threading.Tasks; + using Microsoft.Extensions.DependencyInjection; + using Microsoft.AspNetCore.Builder; + using Dapr.Jobs; + using Dapr.Jobs.Extensions; + using Dapr.Jobs.Models; + + public static class Program + { + public static async Task Main() + { + var builder = WebApplication.CreateBuilder(); + builder.Services.AddDaprJobsClient(); + var app = builder.Build(); + using var scope = app.Services.CreateScope(); + + var daprJobsClient = scope.ServiceProvider.GetRequiredService(); + + await ScheduleJobAsync(""myJob""); + } + + public static Task ScheduleJobAsync(string jobNAme) + { + return Task.CompletedTask; + } + } + "; + + await VerifyAnalyzerAsync(testCode); + } + + private static async Task VerifyAnalyzerAsync(string testCode, params DiagnosticResult[] expectedDiagnostics) + { + var test = new CSharpAnalyzerTest + { + + TestCode = testCode, + }; + + test.TestState.ReferenceAssemblies = referenceAssemblies; + + test.TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(WebApplication).Assembly.Location)); + test.TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(DaprJobsClient).Assembly.Location)); + test.TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(DaprJobSchedule).Assembly.Location)); + test.TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(EndpointRouteBuilderExtensions).Assembly.Location)); + test.TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(IApplicationBuilder).Assembly.Location)); + test.TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile( + typeof(Microsoft.Extensions.DependencyInjection.ServiceCollection).Assembly.Location)); + test.TestState.AdditionalReferences.Add(MetadataReference.CreateFromFile(typeof(IHost).Assembly.Location)); + + test.ExpectedDiagnostics.AddRange(expectedDiagnostics); + await test.RunAsync(); + } + } +} From 2cc9b3ab1ca44a15caf3bc37dc35656f23f59d2e Mon Sep 17 00:00:00 2001 From: Siri Varma Vegiraju Date: Fri, 28 Feb 2025 14:04:36 -0800 Subject: [PATCH 05/10] Add tests Signed-off-by: Siri Varma Vegiraju --- all.sln | 1 + .../ConversationalAI/Properties/launchSettings.json | 12 ------------ .../Properties/launchSettings.json | 12 ------------ 3 files changed, 1 insertion(+), 24 deletions(-) delete mode 100644 examples/AI/ConversationalAI/Properties/launchSettings.json delete mode 100644 examples/Client/PublishSubscribe/StreamingSubscriptionExample/Properties/launchSettings.json diff --git a/all.sln b/all.sln index 57d0b4513..5258f4817 100644 --- a/all.sln +++ b/all.sln @@ -420,6 +420,7 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution + {C2DB4B64-B7C3-4FED-8753-C040F677C69A} = {27C5D71D-0721-4221-9286-B94AB07B58CF} {41BF4392-54BD-4FE7-A3EB-CD045F88CA9A} = {DD020B34-460F-455F-8D17-CF4A949F100B} {B9C12532-0969-4DAC-A2F8-CA9208D7A901} = {27C5D71D-0721-4221-9286-B94AB07B58CF} {62E41317-ED5D-4AA4-B129-C9E56C27354C} = {27C5D71D-0721-4221-9286-B94AB07B58CF} diff --git a/examples/AI/ConversationalAI/Properties/launchSettings.json b/examples/AI/ConversationalAI/Properties/launchSettings.json deleted file mode 100644 index bb6222129..000000000 --- a/examples/AI/ConversationalAI/Properties/launchSettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "profiles": { - "ConversationalAI": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:56624;http://localhost:56625" - } - } -} \ No newline at end of file diff --git a/examples/Client/PublishSubscribe/StreamingSubscriptionExample/Properties/launchSettings.json b/examples/Client/PublishSubscribe/StreamingSubscriptionExample/Properties/launchSettings.json deleted file mode 100644 index afe549903..000000000 --- a/examples/Client/PublishSubscribe/StreamingSubscriptionExample/Properties/launchSettings.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "profiles": { - "StreamingSubscriptionExample": { - "commandName": "Project", - "launchBrowser": true, - "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" - }, - "applicationUrl": "https://localhost:56622;http://localhost:56623" - } - } -} \ No newline at end of file From 17d24fb7d5dcbdce41970d8ebe882260378ddcd3 Mon Sep 17 00:00:00 2001 From: Siri Varma Vegiraju Date: Fri, 28 Feb 2025 14:07:51 -0800 Subject: [PATCH 06/10] remove unnecessary Signed-off-by: Siri Varma Vegiraju --- examples/Jobs/JobsSample/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Jobs/JobsSample/Program.cs b/examples/Jobs/JobsSample/Program.cs index ed1e71528..f19e375b3 100644 --- a/examples/Jobs/JobsSample/Program.cs +++ b/examples/Jobs/JobsSample/Program.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ // Copyright 2024 The Dapr Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. From cc1fe0bd9bb37d49d4f22ef2d258a472044a7e59 Mon Sep 17 00:00:00 2001 From: Siri Varma Vegiraju Date: Fri, 28 Feb 2025 14:19:21 -0800 Subject: [PATCH 07/10] Fix things Signed-off-by: Siri Varma Vegiraju --- src/Dapr.Jobs.Analyzer/AnalyzerReleases.Shipped.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Dapr.Jobs.Analyzer/AnalyzerReleases.Shipped.md b/src/Dapr.Jobs.Analyzer/AnalyzerReleases.Shipped.md index 7725e6165..f3428f064 100644 --- a/src/Dapr.Jobs.Analyzer/AnalyzerReleases.Shipped.md +++ b/src/Dapr.Jobs.Analyzer/AnalyzerReleases.Shipped.md @@ -4,4 +4,4 @@ Rule ID | Category | Severity | Notes --------|----------|----------|-------------------- -DAPRJOBS0001| Usage | Warning | The method 'MapDaprScheduledJobHandler' should be called on 'app' in startup configuration \ No newline at end of file +DAPRJOBS0001| Usage | Warning | There should be a mapping post endpoint for each scheduled job to make sure app receives notifications for all the scheduled jobs \ No newline at end of file From 30803e90b88804a6ef5d807435434b65eca674f6 Mon Sep 17 00:00:00 2001 From: Siri Varma Vegiraju Date: Mon, 3 Mar 2025 12:50:40 -0800 Subject: [PATCH 08/10] Address comments Signed-off-by: Siri Varma Vegiraju --- all.sln | 4 +- examples/Jobs/JobsSample/Program.cs | 2 +- .../AnalyzerReleases.Shipped.md | 2 +- ...yzer.csproj => Dapr.Jobs.Analyzers.csproj} | 0 ... => MapDaprScheduledJobHandlerAnalyzer.cs} | 51 +++-- ...csproj => Dapr.Jobs.Analyzer.Tests.csproj} | 2 +- ...t.cs => MapDaprScheduledJobHandlerTest.cs} | 178 ++---------------- 7 files changed, 40 insertions(+), 199 deletions(-) rename src/Dapr.Jobs.Analyzer/{Dapr.Jobs.Analyzer.csproj => Dapr.Jobs.Analyzers.csproj} (100%) rename src/Dapr.Jobs.Analyzer/{DaprJobsAnalyzerAnalyzer.cs => MapDaprScheduledJobHandlerAnalyzer.cs} (69%) rename test/Dapr.Jobs.Analyzer.Test/{Dapr.Jobs.Analyzer.Test.csproj => Dapr.Jobs.Analyzer.Tests.csproj} (97%) rename test/Dapr.Jobs.Analyzer.Test/{DaprJobAnalyzerTest.cs => MapDaprScheduledJobHandlerTest.cs} (58%) diff --git a/all.sln b/all.sln index 5258f4817..a0edc7240 100644 --- a/all.sln +++ b/all.sln @@ -155,9 +155,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JobsSample", "examples\Jobs EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Workflow.Test", "test\Dapr.Workflow.Test\Dapr.Workflow.Test.csproj", "{E90114C6-86FC-43B8-AE5C-D9273CF21FE4}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Jobs.Analyzer", "src\Dapr.Jobs.Analyzer\Dapr.Jobs.Analyzer.csproj", "{28B87C37-4B52-400F-B84D-64F134931BDC}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Jobs.Analyzers", "src\Dapr.Jobs.Analyzer\Dapr.Jobs.Analyzers.csproj", "{28B87C37-4B52-400F-B84D-64F134931BDC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Jobs.Analyzer.Test", "test\Dapr.Jobs.Analyzer.Test\Dapr.Jobs.Analyzer.Test.csproj", "{CADEAE45-8981-4723-B641-9C28251C7D3B}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Jobs.Analyzer.Tests", "test\Dapr.Jobs.Analyzer.Test\Dapr.Jobs.Analyzer.Tests.csproj", "{CADEAE45-8981-4723-B641-9C28251C7D3B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/examples/Jobs/JobsSample/Program.cs b/examples/Jobs/JobsSample/Program.cs index f19e375b3..ed1e71528 100644 --- a/examples/Jobs/JobsSample/Program.cs +++ b/examples/Jobs/JobsSample/Program.cs @@ -1,4 +1,4 @@ -// ------------------------------------------------------------------------ +// ------------------------------------------------------------------------ // Copyright 2024 The Dapr Authors // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/src/Dapr.Jobs.Analyzer/AnalyzerReleases.Shipped.md b/src/Dapr.Jobs.Analyzer/AnalyzerReleases.Shipped.md index f3428f064..6ad4fd953 100644 --- a/src/Dapr.Jobs.Analyzer/AnalyzerReleases.Shipped.md +++ b/src/Dapr.Jobs.Analyzer/AnalyzerReleases.Shipped.md @@ -4,4 +4,4 @@ Rule ID | Category | Severity | Notes --------|----------|----------|-------------------- -DAPRJOBS0001| Usage | Warning | There should be a mapping post endpoint for each scheduled job to make sure app receives notifications for all the scheduled jobs \ No newline at end of file +DAPRJOBS0001| Usage | Warning | Job invocations require the MapDaprScheduledJobHandler be set and configured for each anticipated job on IEndpointRouteBuilder \ No newline at end of file diff --git a/src/Dapr.Jobs.Analyzer/Dapr.Jobs.Analyzer.csproj b/src/Dapr.Jobs.Analyzer/Dapr.Jobs.Analyzers.csproj similarity index 100% rename from src/Dapr.Jobs.Analyzer/Dapr.Jobs.Analyzer.csproj rename to src/Dapr.Jobs.Analyzer/Dapr.Jobs.Analyzers.csproj diff --git a/src/Dapr.Jobs.Analyzer/DaprJobsAnalyzerAnalyzer.cs b/src/Dapr.Jobs.Analyzer/MapDaprScheduledJobHandlerAnalyzer.cs similarity index 69% rename from src/Dapr.Jobs.Analyzer/DaprJobsAnalyzerAnalyzer.cs rename to src/Dapr.Jobs.Analyzer/MapDaprScheduledJobHandlerAnalyzer.cs index 2bf51d4df..364b7460d 100644 --- a/src/Dapr.Jobs.Analyzer/DaprJobsAnalyzerAnalyzer.cs +++ b/src/Dapr.Jobs.Analyzer/MapDaprScheduledJobHandlerAnalyzer.cs @@ -1,5 +1,4 @@ using System.Collections.Immutable; -using System.Linq; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; @@ -8,15 +7,15 @@ namespace Dapr.Jobs.Analyzer { /// - /// DaprJobsAnalyzerAnalyzer. + /// DaprJobsAnalyzer. /// [DiagnosticAnalyzer(LanguageNames.CSharp)] - public class DaprJobsAnalyzerAnalyzer : DiagnosticAnalyzer + public sealed class MapDaprScheduledJobHandlerAnalyzer : DiagnosticAnalyzer { private static readonly DiagnosticDescriptor DaprJobHandlerRule = new DiagnosticDescriptor( id: "DAPRJOBS0001", title: "Ensure Post Mapper handler is present for all the Scheduled Jobs", - messageFormat: "There should be a mapping post endpoint for each scheduled job to make sure app receives notifications for all the scheduled jobs", + messageFormat: "Job invocations require the MapDaprScheduledJobHandler be set and configured for each anticipated job on IEndpointRouteBuilder", category: "Usage", DiagnosticSeverity.Warning, isEnabledByDefault: true @@ -24,9 +23,8 @@ public class DaprJobsAnalyzerAnalyzer : DiagnosticAnalyzer private static readonly string DaprJobsNameSpace = "Dapr.Jobs"; private static readonly string DaprJobScheduleJobAsyncMethod = "ScheduleJobAsync"; - private static readonly string EndpointNameSpace = "Microsoft.AspNetCore.Builder"; - private static readonly string MapPostMethod = "MapPost"; - private static readonly string DaprJobInvocatoinUrlResource = "job"; + private static readonly string MethodNameSpace = "Dapr.Jobs.Extensions"; + private static readonly string MapDaprScheduledJobHandlerMethod = "MapDaprScheduledJobHandler"; /// public override ImmutableArray SupportedDiagnostics { get { return ImmutableArray.Create(DaprJobHandlerRule); } } @@ -67,29 +65,14 @@ private static void CheckForEndpointRoute(SyntaxNodeAnalysisContext context, str var root = context.SemanticModel.SyntaxTree.GetRoot(); // Search for MapPost with the corresponding route - var endpointMappings = root.DescendantNodes() + int mapDaprScheduledJobHandlersCount = root.DescendantNodes() .OfType() - .Where(invocation => IsNamespaceAndMethodNameEqual(context, invocation, EndpointNameSpace, MapPostMethod)) - .ToList(); + .Where(invocation => IsNamespaceAndMethodNameEqual(context, invocation, MethodNameSpace, MapDaprScheduledJobHandlerMethod)) + .Count(); - foreach (var mapping in endpointMappings) + if (mapDaprScheduledJobHandlersCount > 0) { - // Look for route patterns like "/job/{jobname}" - var argumentExpression = mapping.ArgumentList.Arguments.FirstOrDefault()?.Expression; - string argument = string.Empty; - if (argumentExpression is LiteralExpressionSyntax literal) - { - argument = literal.Token.ValueText; // This extracts the string without quotes - } - - // route patterns like "/job/{jobname} or /job/myJob" - string[] endpointSplit = argument.Split('/'); - if (endpointSplit.Length == 3 - && endpointSplit[1].Equals(DaprJobInvocatoinUrlResource) - && (endpointSplit[2].Equals(jobName) || ((endpointSplit[2].StartsWith("{") && endpointSplit[2].EndsWith("}"))))) - { - return; - } + return; } // If no matching route was found, report a diagnostic @@ -97,6 +80,20 @@ private static void CheckForEndpointRoute(SyntaxNodeAnalysisContext context, str context.ReportDiagnostic(diagnostic); } + /// + /// Determines whether a given method invocation matches a specified method name + /// within a given namespace. + /// + /// For eg: MapDaprScheduledJobHandler (methodname) from the "Dapr.Jobs.Extension" (symbolNamespace) is being called. + /// + /// The syntax analysis context providing semantic information. + /// The invocation expression to analyze. + /// The expected namespace of the method. + /// The expected method name. + /// + /// true if the method belongs to the specified namespace and has the expected name; + /// otherwise, false. + /// private static bool IsNamespaceAndMethodNameEqual(SyntaxNodeAnalysisContext context, InvocationExpressionSyntax invocation, string symbolNamespace, string methodName) { var symbolInfo = context.SemanticModel.GetSymbolInfo(invocation.Expression); diff --git a/test/Dapr.Jobs.Analyzer.Test/Dapr.Jobs.Analyzer.Test.csproj b/test/Dapr.Jobs.Analyzer.Test/Dapr.Jobs.Analyzer.Tests.csproj similarity index 97% rename from test/Dapr.Jobs.Analyzer.Test/Dapr.Jobs.Analyzer.Test.csproj rename to test/Dapr.Jobs.Analyzer.Test/Dapr.Jobs.Analyzer.Tests.csproj index 53f52d98b..57ca6b87a 100644 --- a/test/Dapr.Jobs.Analyzer.Test/Dapr.Jobs.Analyzer.Test.csproj +++ b/test/Dapr.Jobs.Analyzer.Test/Dapr.Jobs.Analyzer.Tests.csproj @@ -25,7 +25,7 @@ - + diff --git a/test/Dapr.Jobs.Analyzer.Test/DaprJobAnalyzerTest.cs b/test/Dapr.Jobs.Analyzer.Test/MapDaprScheduledJobHandlerTest.cs similarity index 58% rename from test/Dapr.Jobs.Analyzer.Test/DaprJobAnalyzerTest.cs rename to test/Dapr.Jobs.Analyzer.Test/MapDaprScheduledJobHandlerTest.cs index 22509f07e..3a15214fb 100644 --- a/test/Dapr.Jobs.Analyzer.Test/DaprJobAnalyzerTest.cs +++ b/test/Dapr.Jobs.Analyzer.Test/MapDaprScheduledJobHandlerTest.cs @@ -1,13 +1,12 @@ namespace Dapr.Jobs.Analyzer.Tests { - using Microsoft.CodeAnalysis.CSharp.Testing; using Microsoft.CodeAnalysis.Testing; using Microsoft.CodeAnalysis; using Microsoft.AspNetCore.Builder; using Dapr.Jobs.Models; - using System.Text; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; + using Microsoft.CodeAnalysis.CSharp.Testing; public class DaprJobsAnalyzerAnalyzerTests { @@ -22,17 +21,6 @@ public class DaprJobsAnalyzerAnalyzerTests private static readonly ReferenceAssemblies referenceAssemblies = ReferenceAssemblies.Net.Net90; #endif - private static readonly DiagnosticDescriptor DaprJobHandlerRule = new DiagnosticDescriptor( -#pragma warning disable RS2008 // Enable analyzer release tracking - id: "DAPRJOBS0001", -#pragma warning restore RS2008 // Enable analyzer release tracking - title: "Ensure Post Mapper handler is present for all the Scheduled Jobs", - messageFormat: "There should be a mapping post endpoint for each scheduled job to make sure app receives notifications for all the scheduled jobs", - category: "Usage", - DiagnosticSeverity.Warning, - isEnabledByDefault: true - ); - [Fact] public async Task AnalyzeJobSchedulerHandler_ShouldRaiseDiagnostic_WhenJobHasNoEndpointMapping() { @@ -62,48 +50,7 @@ public static void Main() } }"; - var expectedDiagnostic = new DiagnosticResult(DaprJobHandlerRule); - - await VerifyAnalyzerAsync(testCode, expectedDiagnostic); - } - - [Fact] - public async Task AnalyzeJobSchedulerHandler_ShouldRaiseDiagnostic_WhenJobHasHasEndpointButDoesNotMapToJobName() - { - var testCode = @" - using System; - using System.Text; - using System.Threading.Tasks; - using Microsoft.Extensions.DependencyInjection; - using Microsoft.AspNetCore.Builder; - using Dapr.Jobs; - using Dapr.Jobs.Extensions; - using Dapr.Jobs.Models; - - public static class Program - { - public static void Main() - { - var builder = WebApplication.CreateBuilder(); - builder.Services.AddDaprJobsClient(); - var app = builder.Build(); - using var scope = app.Services.CreateScope(); - - var daprJobsClient = scope.ServiceProvider.GetRequiredService(); - - daprJobsClient.ScheduleJobAsync(""myJob"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), - Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); - - app.UseEndpoints(endpoints => - { - endpoints.MapPost(""/job/JobA"", async context => - { - }); - }); - } - }"; - - var expectedDiagnostic = new DiagnosticResult(DaprJobHandlerRule); + var expectedDiagnostic = new DiagnosticResult("DAPRJOBS0001", DiagnosticSeverity.Warning); await VerifyAnalyzerAsync(testCode, expectedDiagnostic); } @@ -131,17 +78,10 @@ public static void Main() using var scope = app.Services.CreateScope(); var daprJobsClient = scope.ServiceProvider.GetRequiredService(); - - app.UseEndpoints(endpoints => - { - endpoints.MapPost(""/job/JobA"", async context => - { - }); - }); } }"; - var expectedDiagnostic = new DiagnosticResult(DaprJobHandlerRule); + var expectedDiagnostic = new DiagnosticResult("DAPRJOBS0001", DiagnosticSeverity.Warning); await VerifyAnalyzerAsync(testCode); } @@ -177,97 +117,11 @@ public static void Main() } }"; - var expectedDiagnostic = new DiagnosticResult(DaprJobHandlerRule); + var expectedDiagnostic = new DiagnosticResult("DAPRJOBS0001", DiagnosticSeverity.Warning); await VerifyAnalyzerAsync(testCode, expectedDiagnostic, expectedDiagnostic); } - [Fact] - public async Task AnalyzeJobSchedulerHandler_ShouldRaiseDiagnostic_OnlyOnceWhenOneJobHasMappingAndOtherDoesNot() - { - var testCode = @" - using System; - using System.Text; - using System.Threading.Tasks; - using Microsoft.Extensions.DependencyInjection; - using Microsoft.AspNetCore.Builder; - using Dapr.Jobs; - using Dapr.Jobs.Extensions; - using Dapr.Jobs.Models; - - public static class Program - { - public static void Main() - { - var builder = WebApplication.CreateBuilder(); - builder.Services.AddDaprJobsClient(); - var app = builder.Build(); - using var scope = app.Services.CreateScope(); - - var daprJobsClient = scope.ServiceProvider.GetRequiredService(); - - daprJobsClient.ScheduleJobAsync(""myJob"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), - Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); - daprJobsClient.ScheduleJobAsync(""myJob2"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), - Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); - - app.UseEndpoints(endpoints => - { - endpoints.MapPost(""/job/myJob"", async context => - { - }); - }); - } - }"; - - var expectedDiagnostic = new DiagnosticResult(DaprJobHandlerRule); - - await VerifyAnalyzerAsync(testCode, expectedDiagnostic); - } - - [Fact] - public async Task AnalyzeJobSchedulerHandler_ShouldNotRaiseDiagnostic_WhenTheMappingExistsAsAParameter() - { - var testCode = @" - using System; - using System.Text; - using System.Threading.Tasks; - using Microsoft.Extensions.DependencyInjection; - using Microsoft.AspNetCore.Builder; - using Dapr.Jobs; - using Dapr.Jobs.Extensions; - using Dapr.Jobs.Models; - - public static class Program - { - public static void Main() - { - var builder = WebApplication.CreateBuilder(); - builder.Services.AddDaprJobsClient(); - var app = builder.Build(); - using var scope = app.Services.CreateScope(); - - var daprJobsClient = scope.ServiceProvider.GetRequiredService(); - - daprJobsClient.ScheduleJobAsync(""myJob"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), - Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); - daprJobsClient.ScheduleJobAsync(""myJob1"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), - Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); - daprJobsClient.ScheduleJobAsync(""myJob2"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), - Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); - - app.UseEndpoints(endpoints => - { - endpoints.MapPost(""/job/{myJob}"", async context => - { - }); - }); - } - }"; - - await VerifyAnalyzerAsync(testCode); - } - [Fact] public async Task AnalyzeJobSchedulerHandler_ShouldNotRaiseDiagnostic_WhenJobHasEndpointMapping() @@ -298,15 +152,10 @@ public static void Main() daprJobsClient.ScheduleJobAsync(""myJob2"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), Encoding.UTF8.GetBytes(""This is a test""), repeats: 10).GetAwaiter().GetResult(); - app.UseEndpoints(endpoints => + app.MapDaprScheduledJobHandler(async (string jobName, ReadOnlyMemory jobPayload) => { - endpoints.MapPost(""/job/myJob"", async context => - { - }); - endpoints.MapPost(""/job/myJob2"", async context => - { - }); - }); + return Task.CompletedTask; + }, TimeSpan.FromSeconds(5)); } }"; @@ -342,15 +191,10 @@ public static async Task Main() await daprJobsClient.ScheduleJobAsync(""myJob2"", DaprJobSchedule.FromDuration(TimeSpan.FromSeconds(2)), Encoding.UTF8.GetBytes(""This is a test""), repeats: 10); - app.UseEndpoints(endpoints => + app.MapDaprScheduledJobHandler(async (string jobName, ReadOnlyMemory jobPayload) => { - endpoints.MapPost(""/job/myJob"", async context => - { - }); - endpoints.MapPost(""/job/myJob2"", async context => - { - }); - }); + return Task.CompletedTask; + }, TimeSpan.FromSeconds(5)); } }"; @@ -396,7 +240,7 @@ public static Task ScheduleJobAsync(string jobNAme) private static async Task VerifyAnalyzerAsync(string testCode, params DiagnosticResult[] expectedDiagnostics) { - var test = new CSharpAnalyzerTest + var test = new CSharpAnalyzerTest { TestCode = testCode, From 6b1d45e663ab735cb3a07074987b336fab4b8e5f Mon Sep 17 00:00:00 2001 From: Siri Varma Vegiraju Date: Mon, 17 Mar 2025 07:35:58 -0700 Subject: [PATCH 09/10] Change job id Signed-off-by: Siri Varma Vegiraju --- src/Dapr.Jobs.Analyzer/AnalyzerReleases.Shipped.md | 2 +- .../MapDaprScheduledJobHandlerAnalyzer.cs | 4 ++-- .../MapDaprScheduledJobHandlerTest.cs | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Dapr.Jobs.Analyzer/AnalyzerReleases.Shipped.md b/src/Dapr.Jobs.Analyzer/AnalyzerReleases.Shipped.md index 6ad4fd953..5fab0bb6f 100644 --- a/src/Dapr.Jobs.Analyzer/AnalyzerReleases.Shipped.md +++ b/src/Dapr.Jobs.Analyzer/AnalyzerReleases.Shipped.md @@ -4,4 +4,4 @@ Rule ID | Category | Severity | Notes --------|----------|----------|-------------------- -DAPRJOBS0001| Usage | Warning | Job invocations require the MapDaprScheduledJobHandler be set and configured for each anticipated job on IEndpointRouteBuilder \ No newline at end of file +DAPR3001| Usage | Warning | Job invocations require the MapDaprScheduledJobHandler be set and configured for each anticipated job on IEndpointRouteBuilder \ No newline at end of file diff --git a/src/Dapr.Jobs.Analyzer/MapDaprScheduledJobHandlerAnalyzer.cs b/src/Dapr.Jobs.Analyzer/MapDaprScheduledJobHandlerAnalyzer.cs index 364b7460d..498b78034 100644 --- a/src/Dapr.Jobs.Analyzer/MapDaprScheduledJobHandlerAnalyzer.cs +++ b/src/Dapr.Jobs.Analyzer/MapDaprScheduledJobHandlerAnalyzer.cs @@ -13,7 +13,7 @@ namespace Dapr.Jobs.Analyzer public sealed class MapDaprScheduledJobHandlerAnalyzer : DiagnosticAnalyzer { private static readonly DiagnosticDescriptor DaprJobHandlerRule = new DiagnosticDescriptor( - id: "DAPRJOBS0001", + id: "DAPR3001", title: "Ensure Post Mapper handler is present for all the Scheduled Jobs", messageFormat: "Job invocations require the MapDaprScheduledJobHandler be set and configured for each anticipated job on IEndpointRouteBuilder", category: "Usage", @@ -65,7 +65,7 @@ private static void CheckForEndpointRoute(SyntaxNodeAnalysisContext context, str var root = context.SemanticModel.SyntaxTree.GetRoot(); // Search for MapPost with the corresponding route - int mapDaprScheduledJobHandlersCount = root.DescendantNodes() + var mapDaprScheduledJobHandlersCount = root.DescendantNodes() .OfType() .Where(invocation => IsNamespaceAndMethodNameEqual(context, invocation, MethodNameSpace, MapDaprScheduledJobHandlerMethod)) .Count(); diff --git a/test/Dapr.Jobs.Analyzer.Test/MapDaprScheduledJobHandlerTest.cs b/test/Dapr.Jobs.Analyzer.Test/MapDaprScheduledJobHandlerTest.cs index 3a15214fb..f5bb3d9c4 100644 --- a/test/Dapr.Jobs.Analyzer.Test/MapDaprScheduledJobHandlerTest.cs +++ b/test/Dapr.Jobs.Analyzer.Test/MapDaprScheduledJobHandlerTest.cs @@ -50,7 +50,7 @@ public static void Main() } }"; - var expectedDiagnostic = new DiagnosticResult("DAPRJOBS0001", DiagnosticSeverity.Warning); + var expectedDiagnostic = new DiagnosticResult("DAPR3001", DiagnosticSeverity.Warning); await VerifyAnalyzerAsync(testCode, expectedDiagnostic); } @@ -81,7 +81,7 @@ public static void Main() } }"; - var expectedDiagnostic = new DiagnosticResult("DAPRJOBS0001", DiagnosticSeverity.Warning); + var expectedDiagnostic = new DiagnosticResult("DAPR3001", DiagnosticSeverity.Warning); await VerifyAnalyzerAsync(testCode); } @@ -117,7 +117,7 @@ public static void Main() } }"; - var expectedDiagnostic = new DiagnosticResult("DAPRJOBS0001", DiagnosticSeverity.Warning); + var expectedDiagnostic = new DiagnosticResult("DAPR3001", DiagnosticSeverity.Warning); await VerifyAnalyzerAsync(testCode, expectedDiagnostic, expectedDiagnostic); } From d3e5334a6210dc65330fd9d5669ba315c0e16fb4 Mon Sep 17 00:00:00 2001 From: Siri Varma Vegiraju Date: Mon, 17 Mar 2025 07:49:44 -0700 Subject: [PATCH 10/10] Remove .net6,7 Signed-off-by: Siri Varma Vegiraju --- .../MapDaprScheduledJobHandlerTest.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/Dapr.Jobs.Analyzer.Test/MapDaprScheduledJobHandlerTest.cs b/test/Dapr.Jobs.Analyzer.Test/MapDaprScheduledJobHandlerTest.cs index f5bb3d9c4..4db2198ba 100644 --- a/test/Dapr.Jobs.Analyzer.Test/MapDaprScheduledJobHandlerTest.cs +++ b/test/Dapr.Jobs.Analyzer.Test/MapDaprScheduledJobHandlerTest.cs @@ -11,11 +11,7 @@ public class DaprJobsAnalyzerAnalyzerTests { -#if NET6_0 - private static readonly ReferenceAssemblies referenceAssemblies = ReferenceAssemblies.Net.Net60; -#elif NET7_0 - private static readonly ReferenceAssemblies referenceAssemblies = ReferenceAssemblies.Net.Net70; -#elif NET8_0 +#if NET8_0 private static readonly ReferenceAssemblies referenceAssemblies = ReferenceAssemblies.Net.Net80; #elif NET9_0 private static readonly ReferenceAssemblies referenceAssemblies = ReferenceAssemblies.Net.Net90;