From 48e37a86ebdff95caead0c42bba735882d125e8d Mon Sep 17 00:00:00 2001 From: JobaDiniz Date: Thu, 26 Oct 2023 15:13:10 -0300 Subject: [PATCH 1/2] test(fitness): add architecture fitness tests Signed-off-by: JobaDiniz --- .../AccountAuthenticatorFactory.cs} | 38 ++++++++++++++++++- .../Client/RpaClientFactory.cs | 2 +- .../Client/RpaHttpClientFactory.cs | 6 +++ .../Account/IAccountAuthenticator.cs | 26 ------------- src/Joba.IBM.RPA/Account/WdgAuthenticator.cs | 12 ------ src/Joba.IBM.RPA/IRpaClient.cs | 6 --- src/Joba.IBM.RPA/Pipeline/AsyncPipeline.cs | 2 +- .../Pipeline/DefaultPipelineMiddleware.cs | 2 +- src/Joba.IBM.RPA/Pipeline/IAsyncMiddleware.cs | 2 +- src/Joba.IBM.RPA/Pipeline/IAsyncPipeline.cs | 2 +- .../Pipeline/PipelineExceptionSource.cs | 2 +- .../Fitness/ArchitectureShould.cs | 37 ++++++++++++++++++ .../Joba.IBM.RPA.Tests/Fitness/readme.md | 11 ++++++ .../Joba.IBM.RPA.Tests.csproj | 1 + 14 files changed, 98 insertions(+), 51 deletions(-) rename src/{Joba.IBM.RPA/Account/RedHatOpenshiftOidcAuthenticator.cs => Joba.IBM.RPA.Cli/AccountAuthenticatorFactory.cs} (80%) delete mode 100644 src/Joba.IBM.RPA/Account/WdgAuthenticator.cs create mode 100644 src/Tests/Joba.IBM.RPA.Tests/Fitness/ArchitectureShould.cs create mode 100644 src/Tests/Joba.IBM.RPA.Tests/Fitness/readme.md diff --git a/src/Joba.IBM.RPA/Account/RedHatOpenshiftOidcAuthenticator.cs b/src/Joba.IBM.RPA.Cli/AccountAuthenticatorFactory.cs similarity index 80% rename from src/Joba.IBM.RPA/Account/RedHatOpenshiftOidcAuthenticator.cs rename to src/Joba.IBM.RPA.Cli/AccountAuthenticatorFactory.cs index 0519c24..37f8abf 100644 --- a/src/Joba.IBM.RPA/Account/RedHatOpenshiftOidcAuthenticator.cs +++ b/src/Joba.IBM.RPA.Cli/AccountAuthenticatorFactory.cs @@ -1,8 +1,44 @@ using Joba.IBM.RPA.Server; using System.Net.Http.Json; -namespace Joba.IBM.RPA +namespace Joba.IBM.RPA.Cli { + internal class AccountAuthenticatorFactory : IAccountAuthenticatorFactory + { + private readonly IRpaClientFactory clientFactory; + private readonly IRpaHttpClientFactory httpFactory; + + public AccountAuthenticatorFactory(IRpaClientFactory clientFactory, IRpaHttpClientFactory httpFactory) + { + this.clientFactory = clientFactory; + this.httpFactory = httpFactory; + } + + IAccountAuthenticator IAccountAuthenticatorFactory.Create(DeploymentOption deployment, AuthenticationMethod authenticationMethod, Region region, PropertyOptions properties) + { + if (deployment == DeploymentOption.OCP && authenticationMethod == AuthenticationMethod.OIDC) + { + var cloudPakAddress = properties[PropertyOptions.CloudPakConsoleAddress]; + return cloudPakAddress == null + ? throw new NotSupportedException($"Since the server is deployed in the CloudPak cluster, the CloudPak Console URL is required and it was not provided. More information https://ibm.github.io/ibm-rpa-cli/#/guide/environment?id=red-hat®-openshift®-support-with-single-sign-on.") + : (IAccountAuthenticator)new RedHatOpenshiftOidcAuthenticator(httpFactory, region, new Uri(cloudPakAddress)); + } + + var client = clientFactory.CreateFromRegion(region); + return new WdgAuthenticator(client.Account); + } + } + + class WdgAuthenticator : IAccountAuthenticator + { + private readonly IAccountResource resource; + + public WdgAuthenticator(IAccountResource resource) => this.resource = resource; + + async Task IAccountAuthenticator.AuthenticateAsync(AccountCredentials credentials, CancellationToken cancellation) => + await resource.AuthenticateAsync(credentials.TenantCode, credentials.UserName, credentials.Password, cancellation); + } + class RedHatOpenshiftOidcAuthenticator : IAccountAuthenticator { private readonly IRpaHttpClientFactory httpFactory; diff --git a/src/Joba.IBM.RPA.Cli/Client/RpaClientFactory.cs b/src/Joba.IBM.RPA.Cli/Client/RpaClientFactory.cs index a2a5ab8..346ce12 100644 --- a/src/Joba.IBM.RPA.Cli/Client/RpaClientFactory.cs +++ b/src/Joba.IBM.RPA.Cli/Client/RpaClientFactory.cs @@ -2,7 +2,7 @@ namespace Joba.IBM.RPA.Cli { - public class RpaClientFactory : IRpaClientFactory + internal class RpaClientFactory : IRpaClientFactory { private readonly IConsole console; private readonly IRpaHttpClientFactory httpFactory; diff --git a/src/Joba.IBM.RPA.Cli/Client/RpaHttpClientFactory.cs b/src/Joba.IBM.RPA.Cli/Client/RpaHttpClientFactory.cs index 4885113..886afa0 100644 --- a/src/Joba.IBM.RPA.Cli/Client/RpaHttpClientFactory.cs +++ b/src/Joba.IBM.RPA.Cli/Client/RpaHttpClientFactory.cs @@ -7,6 +7,12 @@ namespace Joba.IBM.RPA.Cli { + internal interface IRpaHttpClientFactory + { + HttpClient Create(Uri address); + HttpClient Create(Uri address, IRenewExpiredSession sessionRenewal); + } + internal class RpaHttpClientFactory : IRpaHttpClientFactory { private const int MaxParallelism = 10; diff --git a/src/Joba.IBM.RPA/Account/IAccountAuthenticator.cs b/src/Joba.IBM.RPA/Account/IAccountAuthenticator.cs index 35c44ea..5057402 100644 --- a/src/Joba.IBM.RPA/Account/IAccountAuthenticator.cs +++ b/src/Joba.IBM.RPA/Account/IAccountAuthenticator.cs @@ -9,30 +9,4 @@ public interface IAccountAuthenticatorFactory { IAccountAuthenticator Create(DeploymentOption deployment, AuthenticationMethod authenticationMethod, Region region, PropertyOptions properties); } - - public class AccountAuthenticatorFactory : IAccountAuthenticatorFactory - { - private readonly IRpaClientFactory clientFactory; - private readonly IRpaHttpClientFactory httpFactory; - - public AccountAuthenticatorFactory(IRpaClientFactory clientFactory, IRpaHttpClientFactory httpFactory) - { - this.clientFactory = clientFactory; - this.httpFactory = httpFactory; - } - - IAccountAuthenticator IAccountAuthenticatorFactory.Create(DeploymentOption deployment, AuthenticationMethod authenticationMethod, Region region, PropertyOptions properties) - { - if (deployment == DeploymentOption.OCP && authenticationMethod == AuthenticationMethod.OIDC) - { - var cloudPakAddress = properties[PropertyOptions.CloudPakConsoleAddress]; - return cloudPakAddress == null - ? throw new NotSupportedException($"Since the server is deployed in the CloudPak cluster, the CloudPak Console URL is required and it was not provided. More information https://ibm.github.io/ibm-rpa-cli/#/guide/environment?id=red-hat®-openshift®-support-with-single-sign-on.") - : (IAccountAuthenticator)new RedHatOpenshiftOidcAuthenticator(httpFactory, region, new Uri(cloudPakAddress)); - } - - var client = clientFactory.CreateFromRegion(region); - return new WdgAuthenticator(client.Account); - } - } } diff --git a/src/Joba.IBM.RPA/Account/WdgAuthenticator.cs b/src/Joba.IBM.RPA/Account/WdgAuthenticator.cs deleted file mode 100644 index 0d02411..0000000 --- a/src/Joba.IBM.RPA/Account/WdgAuthenticator.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Joba.IBM.RPA -{ - class WdgAuthenticator : IAccountAuthenticator - { - private readonly IAccountResource resource; - - public WdgAuthenticator(IAccountResource resource) => this.resource = resource; - - async Task IAccountAuthenticator.AuthenticateAsync(AccountCredentials credentials, CancellationToken cancellation) => - await resource.AuthenticateAsync(credentials.TenantCode, credentials.UserName, credentials.Password, cancellation); - } -} diff --git a/src/Joba.IBM.RPA/IRpaClient.cs b/src/Joba.IBM.RPA/IRpaClient.cs index 851338e..5047b08 100644 --- a/src/Joba.IBM.RPA/IRpaClient.cs +++ b/src/Joba.IBM.RPA/IRpaClient.cs @@ -25,12 +25,6 @@ public interface IRpaClientFactory IRpaClient CreateFromPackageSource(PackageSource source); } - public interface IRpaHttpClientFactory - { - HttpClient Create(Uri address); - HttpClient Create(Uri address, IRenewExpiredSession sessionRenewal); - } - public interface IRenewExpiredSession { Task RenewAsync(CancellationToken cancellation); diff --git a/src/Joba.IBM.RPA/Pipeline/AsyncPipeline.cs b/src/Joba.IBM.RPA/Pipeline/AsyncPipeline.cs index 55bbdbd..631e097 100644 --- a/src/Joba.IBM.RPA/Pipeline/AsyncPipeline.cs +++ b/src/Joba.IBM.RPA/Pipeline/AsyncPipeline.cs @@ -5,7 +5,7 @@ /// Based on: https://github.com/ipvalverde/PipelineNet /// /// The parameter type. - public sealed class AsyncPipeline : IAsyncPipeline + sealed class AsyncPipeline : IAsyncPipeline { private readonly IList> middlewares; private IAsyncMiddleware @finally = EmptyMiddleware.None; diff --git a/src/Joba.IBM.RPA/Pipeline/DefaultPipelineMiddleware.cs b/src/Joba.IBM.RPA/Pipeline/DefaultPipelineMiddleware.cs index 68266a8..c7a1e78 100644 --- a/src/Joba.IBM.RPA/Pipeline/DefaultPipelineMiddleware.cs +++ b/src/Joba.IBM.RPA/Pipeline/DefaultPipelineMiddleware.cs @@ -4,7 +4,7 @@ /// Default implementation of . /// /// - public abstract class DefaultPipelineMiddleware : IAsyncMiddleware + abstract class DefaultPipelineMiddleware : IAsyncMiddleware { /// /// Override this method to implement the middleware logic. diff --git a/src/Joba.IBM.RPA/Pipeline/IAsyncMiddleware.cs b/src/Joba.IBM.RPA/Pipeline/IAsyncMiddleware.cs index be003e6..f6ff4d1 100644 --- a/src/Joba.IBM.RPA/Pipeline/IAsyncMiddleware.cs +++ b/src/Joba.IBM.RPA/Pipeline/IAsyncMiddleware.cs @@ -4,7 +4,7 @@ /// Defines a piece of code (a step) to be executed inside a pipeline. /// /// The parameter type. - public interface IAsyncMiddleware + interface IAsyncMiddleware { /// /// Runs this middleware and enables calling the next middleware. diff --git a/src/Joba.IBM.RPA/Pipeline/IAsyncPipeline.cs b/src/Joba.IBM.RPA/Pipeline/IAsyncPipeline.cs index 1bb3d2f..4ab48eb 100644 --- a/src/Joba.IBM.RPA/Pipeline/IAsyncPipeline.cs +++ b/src/Joba.IBM.RPA/Pipeline/IAsyncPipeline.cs @@ -4,7 +4,7 @@ /// Defines and executes a pipeline. /// /// The parameter type. - public interface IAsyncPipeline + interface IAsyncPipeline { /// /// Adds a middleware. diff --git a/src/Joba.IBM.RPA/Pipeline/PipelineExceptionSource.cs b/src/Joba.IBM.RPA/Pipeline/PipelineExceptionSource.cs index 8b287ef..856d732 100644 --- a/src/Joba.IBM.RPA/Pipeline/PipelineExceptionSource.cs +++ b/src/Joba.IBM.RPA/Pipeline/PipelineExceptionSource.cs @@ -3,7 +3,7 @@ /// /// Defines the exception structure of a pipeline. /// - public sealed class PipelineExceptionSource + sealed class PipelineExceptionSource { public PipelineExceptionSource(Exception ex) { diff --git a/src/Tests/Joba.IBM.RPA.Tests/Fitness/ArchitectureShould.cs b/src/Tests/Joba.IBM.RPA.Tests/Fitness/ArchitectureShould.cs new file mode 100644 index 0000000..6ce07ec --- /dev/null +++ b/src/Tests/Joba.IBM.RPA.Tests/Fitness/ArchitectureShould.cs @@ -0,0 +1,37 @@ +using ArchUnitNET.Domain; +using ArchUnitNET.Loader; +using ArchUnitNET.xUnit; +using static ArchUnitNET.Fluent.ArchRuleDefinition; + +namespace Joba.IBM.RPA.Tests +{ + public class ArchitectureShould + { + private static readonly System.Reflection.Assembly[] assemblies = new System.Reflection.Assembly[] { typeof(IProject).Assembly }; + private static readonly Architecture architecture = new ArchLoader().LoadAssemblies(assemblies).Build(); + + [Fact] + public void DisallowUsingHttpClient() + { + var rule = Types().Should().NotDependOnAny(typeof(HttpClient)) + .Because($"'{string.Join(", ", assemblies.Select(a => a.GetName().Name))}' require(s) using abstractions '{nameof(IRpaClient)} or {nameof(IRpaClientFactory)}'"); + rule.Check(architecture); + } + + [Fact] + public void EnsureSameNamespace() + { + var rule = Types().That().ArePublic().Should().ResideInNamespace(@"Joba.IBM.RPA(\.Server)?", useRegularExpressions: true) + .Because("exposing many namespaces is a bad practice."); + rule.Check(architecture); + } + + //[Fact] + //public void DisallowReferencingSystemCommandLinePackage() + //{ + // //ArchUnitTEST does not support + // //See: https://github.com/TNG/ArchUnitNET/issues/130 + // //See: https://gaevoy.com/2022/05/19/review-dependencies-on-every-commit.html + //} + } +} diff --git a/src/Tests/Joba.IBM.RPA.Tests/Fitness/readme.md b/src/Tests/Joba.IBM.RPA.Tests/Fitness/readme.md new file mode 100644 index 0000000..fc44f96 --- /dev/null +++ b/src/Tests/Joba.IBM.RPA.Tests/Fitness/readme.md @@ -0,0 +1,11 @@ +# Fitness functions +This directory contains fitness functions implemented as tests. + +## What are fitness functions? +> Any mechanism that performs an objective integrity assessment of some architecture characteristic or combination of architecture characteristics. + +In the RPA CLI project, we implement fitness functions as a mechanism to test the **architecture** of the system, enforcing rules to be followed by developers, like forbidding some library packages to be installed in the *Joba.IBM.RPA* core project. + +## More details +- Article: [The Up-and-Running Guide to Architectural Fitness Functions](https://betterprogramming.pub/the-up-and-running-guide-to-architectural-fitness-functions-1621ebe46ea). +- Book: [Fundamentals of Software Architecture: An Engineering Approach](https://www.amazon.com/Fundamentals-Software-Architecture-Comprehensive-Characteristics/dp/1492043451). \ No newline at end of file diff --git a/src/Tests/Joba.IBM.RPA.Tests/Joba.IBM.RPA.Tests.csproj b/src/Tests/Joba.IBM.RPA.Tests/Joba.IBM.RPA.Tests.csproj index ae74769..48e99fe 100644 --- a/src/Tests/Joba.IBM.RPA.Tests/Joba.IBM.RPA.Tests.csproj +++ b/src/Tests/Joba.IBM.RPA.Tests/Joba.IBM.RPA.Tests.csproj @@ -10,6 +10,7 @@ + From d9286588664b9e71d251a63cfac44795e7991c0e Mon Sep 17 00:00:00 2001 From: JobaDiniz Date: Fri, 27 Oct 2023 08:44:09 -0300 Subject: [PATCH 2/2] refactor(pull): pull directory created Signed-off-by: JobaDiniz --- src/Joba.IBM.RPA/{ => Account}/SessionManager.cs | 0 src/Joba.IBM.RPA/{ => Pull}/PullService.Parameter.cs | 0 src/Joba.IBM.RPA/{ => Pull}/PullService.Wal.cs | 0 src/Joba.IBM.RPA/{ => Pull}/PullService.cs | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/Joba.IBM.RPA/{ => Account}/SessionManager.cs (100%) rename src/Joba.IBM.RPA/{ => Pull}/PullService.Parameter.cs (100%) rename src/Joba.IBM.RPA/{ => Pull}/PullService.Wal.cs (100%) rename src/Joba.IBM.RPA/{ => Pull}/PullService.cs (100%) diff --git a/src/Joba.IBM.RPA/SessionManager.cs b/src/Joba.IBM.RPA/Account/SessionManager.cs similarity index 100% rename from src/Joba.IBM.RPA/SessionManager.cs rename to src/Joba.IBM.RPA/Account/SessionManager.cs diff --git a/src/Joba.IBM.RPA/PullService.Parameter.cs b/src/Joba.IBM.RPA/Pull/PullService.Parameter.cs similarity index 100% rename from src/Joba.IBM.RPA/PullService.Parameter.cs rename to src/Joba.IBM.RPA/Pull/PullService.Parameter.cs diff --git a/src/Joba.IBM.RPA/PullService.Wal.cs b/src/Joba.IBM.RPA/Pull/PullService.Wal.cs similarity index 100% rename from src/Joba.IBM.RPA/PullService.Wal.cs rename to src/Joba.IBM.RPA/Pull/PullService.Wal.cs diff --git a/src/Joba.IBM.RPA/PullService.cs b/src/Joba.IBM.RPA/Pull/PullService.cs similarity index 100% rename from src/Joba.IBM.RPA/PullService.cs rename to src/Joba.IBM.RPA/Pull/PullService.cs