Skip to content

Commit

Permalink
Package deactivation (#244)
Browse files Browse the repository at this point in the history
* IApplicationClient.cs added the method ExecutePostRequest<T> to perform post request and return a deserialized response.

* added deactivate package command.

---------

Co-authored-by: S.Liaskivskyi <[email protected]>
  • Loading branch information
lsv-sergio and s-liaskivskyi authored Nov 23, 2023
1 parent a6218b5 commit b50d799
Show file tree
Hide file tree
Showing 8 changed files with 328 additions and 2 deletions.
47 changes: 47 additions & 0 deletions clio.tests/Command/DeactivatePackageCommand.Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using Clio.Command.PackageCommand;
using Clio.Common;
using Clio.Package;
using NSubstitute;
using NUnit.Framework;

namespace Clio.Tests.Command;

[TestFixture]
public class DeactivatePackageCommandTestCase {

#region Methods: Public

[Test, Category("Unit")]
public void Execute_DeactivatesPackage()
{
var packageDeactivator = Substitute.For<IPackageDeactivator>();
var applicationClient = Substitute.For<IApplicationClient>();
var logger = Substitute.For<ILogger>();
var packageName = "TestPackageName";
packageDeactivator.Deactivate(packageName);
var command = new DeactivatePackageCommand(packageDeactivator, applicationClient, new EnvironmentSettings(), logger);
Assert.AreEqual(0, command.Execute(new DeactivatePkgOptions { PackageName = packageName }));
logger.Received().WriteLine($"Start deactivation package: \"{packageName}\"");
logger.Received().WriteLine($"Package \"{packageName}\" successfully deactivated.");
}

[Test, Category("Unit")]
public void Execute_ShowsErrorMessage_WhenPackageWasNotDeactivated()
{
var packageDeactivator = Substitute.For<IPackageDeactivator>();
var applicationClient = Substitute.For<IApplicationClient>();
var logger = Substitute.For<ILogger>();
var packageName = "TestPackageName";
var errorMessage = "SomeErrorMessage";
packageDeactivator.When(deactivator => deactivator.Deactivate(packageName)).Throw(new Exception(errorMessage));
var command = new DeactivatePackageCommand(packageDeactivator, applicationClient, new EnvironmentSettings(), logger);
Assert.AreEqual(1, command.Execute(new DeactivatePkgOptions { PackageName = packageName}));
logger.Received().WriteLine($"Start deactivation package: \"{packageName}\"");
logger.Received().WriteLine(errorMessage);
logger.DidNotReceive().WriteLine($"Package \"{packageName}\" successfully deactivated.");
}

#endregion

}
105 changes: 105 additions & 0 deletions clio.tests/Package/PackageDeactivator.Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Clio.Common;
using Clio.Common.Responses;
using Clio.Package;
using NSubstitute;
using NUnit.Framework;

namespace Clio.Tests.Package;

[TestFixture]
public class PackageDeactivatorTestCase
{
#region Properties: Private

private IApplicationPackageListProvider _applicationPackageListProvider;
private IApplicationClient _applicationClient;
private IServiceUrlBuilder _serviceUrlBuilder;
private PackageDeactivator _packageDeactivator;

#endregion

#region Methods: Private

private static PackageInfo CreatePackageInfo(string packageName, Guid? packageUId = null)
{
return new PackageInfo(new PackageDescriptor { Name = packageName, UId = packageUId ?? Guid.NewGuid() },
string.Empty,
Enumerable.Empty<string>());
}

#endregion

#region Methods: Public

[SetUp]
public void Init()
{
_applicationPackageListProvider = Substitute.For<IApplicationPackageListProvider>();
_applicationClient = Substitute.For<IApplicationClient>();
_serviceUrlBuilder = Substitute.For<IServiceUrlBuilder>();
_packageDeactivator = new PackageDeactivator(_applicationPackageListProvider, _applicationClient,
_serviceUrlBuilder);
}

[Test, Category("Unit")]
public void Deactivate_DeactivatesPackageByName()
{
const string packageName = "TestPackageName";
Guid packageUId = Guid.NewGuid();
_applicationPackageListProvider.GetPackages("{}").Returns(new List<PackageInfo>
{
CreatePackageInfo("SomePackage"),
CreatePackageInfo(packageName, packageUId),
CreatePackageInfo("SomePackage1")
});
const string fullUrl = "TestUrl";
_serviceUrlBuilder.Build("/ServiceModel/PackageService.svc/DeactivatePackage").Returns(fullUrl);
_applicationClient.ExecutePostRequest<BaseResponse>(fullUrl,
Arg.Is<string>(data => data.Contains(packageUId.ToString())))
.Returns(new BaseResponse { Success = true });
Assert.DoesNotThrow(() => _packageDeactivator.Deactivate(packageName));
}

[Test, Category("Unit")]
[TestCase("")]
[TestCase(null)]
public void Deactivate_ThrowsException_WhenPackageByNameIsNotValid(string packageName)
{
Assert.Throws<ArgumentNullException>(() => _packageDeactivator.Deactivate(packageName));
}

[Test, Category("Unit")]
public void Deactivate_ThrowsException_WhenPackageNotFoundByName()
{
const string packageName = "TestPackageName";
_applicationPackageListProvider.GetPackages("{}").Returns(new List<PackageInfo>
{
CreatePackageInfo("SomePackage")
});
Assert.Throws<Exception>(() => _packageDeactivator.Deactivate(packageName),
$"Package with name {packageName} not found");
}

[Test, Category("Unit")]
public void Deactivate_ThrowsException_WhenPackageWasNotBeenDeactivated()
{
const string packageName = "TestPackageName";
Guid packageUId = Guid.NewGuid();
const string errorMessage = "Some error";
_applicationPackageListProvider.GetPackages("{}").Returns(new List<PackageInfo>
{
CreatePackageInfo(packageName, packageUId),
});
_applicationClient.ExecutePostRequest<BaseResponse>(Arg.Any<string>(),
Arg.Is<string>(data => data.Contains(packageUId.ToString())))
.Returns(new BaseResponse { Success = false, ErrorInfo = new ErrorInfo {Message = errorMessage}});

Assert.Throws<Exception>(() => _packageDeactivator.Deactivate(packageName), errorMessage);
}

#endregion

}
1 change: 1 addition & 0 deletions clio/BindingsModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ public IContainer Register(EnvironmentSettings settings = null) {
containerBuilder.RegisterType<SetFsmConfigOptionsValidator>();
containerBuilder.RegisterType<UnzipRequestValidator>();
containerBuilder.RegisterType<GitSyncCommand>();
containerBuilder.RegisterType<DeactivatePackageCommand>();

return containerBuilder.Build();
}
Expand Down
56 changes: 56 additions & 0 deletions clio/Command/PackageCommand/DeactivatePackageCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;
using Clio.Common;
using Clio.Package;

namespace Clio.Command.PackageCommand
{
using CommandLine;

[Verb("deactivate-pkg", HelpText = "Deactivate package from a web application. Will be available in 8.1.2")]
internal class DeactivatePkgOptions : EnvironmentOptions {
[Value(0, MetaName = "Name", Required = true, HelpText = "Package name")]
public string PackageName {
get; set;
}
}

#region Class: GetPackageVersionCommand

internal class DeactivatePackageCommand : RemoteCommand<DeactivatePkgOptions> {
private readonly IPackageDeactivator _packageDeactivator;
private readonly ILogger _logger;

#region Constructors: Public

public DeactivatePackageCommand(IPackageDeactivator packageDeactivator, IApplicationClient applicationClient,
EnvironmentSettings environmentSettings, ILogger logger)
: base(applicationClient, environmentSettings) {
_packageDeactivator = packageDeactivator;
_logger = logger;
}

#endregion

#region Methods: Public

public override int Execute(DeactivatePkgOptions options) {
try {
string packageName = options.PackageName;
_logger.WriteLine($"Start deactivation package: \"{packageName}\"");
_packageDeactivator.Deactivate(packageName);
_logger.WriteLine($"Package \"{packageName}\" successfully deactivated.");
return 0;
}
catch (Exception e) {
_logger.WriteLine(e.Message);
return 1;
}
}

#endregion

}

#endregion

}
23 changes: 22 additions & 1 deletion clio/Common/IApplicationClient.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Creatio.Client;
using System;
using System.Threading;
using Clio.Common.Responses;

namespace Clio.Common
{
Expand All @@ -10,9 +11,12 @@ public interface IApplicationClient
void DownloadFile(string url, string filePath, string requestData);
string ExecuteGetRequest(string url, int requestTimeout = Timeout.Infinite);
string ExecutePostRequest(string url, string requestData, int requestTimeout = Timeout.Infinite);

void Login();
string UploadFile(string url, string filePath);
string UploadAlmFile(string url, string filePath);

T ExecutePostRequest<T>(string url, string requestData, int requestTimeout = Timeout.Infinite) where T: BaseResponse, new();
}

public class CreatioClientAdapter : IApplicationClient
Expand Down Expand Up @@ -63,5 +67,22 @@ internal T As<T>()
{
throw new NotImplementedException();
}
}

/// <summary>
/// Performs post request and returns deserialized response.
/// </summary>
/// <param name="url">Request url.</param>
/// <param name="requestData">Request data.</param>
/// <param name="requestTimeout">Request timeout. Default: infinity period.</param>
/// <typeparam name="T">Return value type.</typeparam>
/// <returns>Response.<see cref="T"/></returns>
public T ExecutePostRequest<T>(string url, string requestData, int requestTimeout = Timeout.Infinite)
where T: BaseResponse, new() {
var converter = new JsonConverter();
string response = _creatioClient.ExecutePostRequest(url, requestData, requestTimeout);
return converter.DeserializeObject<T>(response);
}


}
}
21 changes: 21 additions & 0 deletions clio/Package/IPackageDeactivator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace Clio.Package;

#region Interface: IPackageDeactivator

/// <summary>
/// Provides interface for package deactivation.
/// </summary>
public interface IPackageDeactivator {

#region Methods: Internal

/// <summary>
/// Deactivate package by UId.
/// </summary>
/// <param name="packageName"></param>
void Deactivate(string packageName);

#endregion
}

#endregion
73 changes: 73 additions & 0 deletions clio/Package/PackageDeactivator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System;
using System.Linq;
using Clio.Common;
using Clio.Common.Responses;

namespace Clio.Package;

/// <inheritdoc cref="IPackageDeactivator"/>
internal class PackageDeactivator: IPackageDeactivator
{
#region Fields: Private

private readonly IApplicationPackageListProvider _applicationPackageListProvider;
private readonly IApplicationClient _applicationClient;
private readonly IServiceUrlBuilder _serviceUrlBuilder;

#endregion

#region Constructors: Public

public PackageDeactivator(IApplicationPackageListProvider applicationPackageListProvider,
IApplicationClient applicationClient, IServiceUrlBuilder serviceUrlBuilder) {
_applicationPackageListProvider = applicationPackageListProvider;
_applicationClient = applicationClient;
_serviceUrlBuilder = serviceUrlBuilder;
}

#endregion

#region Methods: Private

private static string CreateRequestData(Guid packageUId) {
return "\"" + packageUId + "\"";
}
private static void ThrowsErrorIfUnsuccessfulResponseReceived(BaseResponse deactivateResponse) {
if (deactivateResponse.Success) {
return;
}
throw new Exception(deactivateResponse.ErrorInfo.Message);
}

private BaseResponse SendDeactivateRequest(Guid packageUId) {
return _applicationClient.ExecutePostRequest<BaseResponse>(
_serviceUrlBuilder.Build("/ServiceModel/PackageService.svc/DeactivatePackage"),
CreateRequestData(packageUId));
}

private Guid GetPackageUId(string packageName) {
PackageInfo packageInfo =
_applicationPackageListProvider.GetPackages("{}")
.FirstOrDefault(package => package.Descriptor.Name == packageName);
if (packageInfo is null) {
throw new Exception($"Package with name {packageName} not found");
}

return packageInfo.Descriptor.UId;
}

#endregion

#region Methods: Public

/// <inheritdoc cref="IPackageDeactivator.Deactivate"/>
public void Deactivate(string packageName) {
packageName.CheckArgumentNullOrWhiteSpace(nameof(packageName));
Guid packageUId = GetPackageUId(packageName);
BaseResponse deactivateResponse = SendDeactivateRequest(packageUId);
ThrowsErrorIfUnsuccessfulResponseReceived(deactivateResponse);
}

#endregion

}
4 changes: 3 additions & 1 deletion clio/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,8 @@ private static int ConvertPackage(ConvertOptions opts)
typeof(CreateInfrastructureOptions),
typeof(OpenInfrastructureOptions),
typeof(CheckWindowsFeaturesOptions),
typeof(CreateTestProjectOptions)
typeof(CreateTestProjectOptions),
typeof(DeactivatePkgOptions)
};
public static Func<object, int> ExecuteCommandWithOption = (instance) => {
return instance switch {
Expand Down Expand Up @@ -634,6 +635,7 @@ private static int ConvertPackage(ConvertOptions opts)
(OpenInfrastructureOptions opts) => Resolve<OpenInfrastructureCommand>().Execute(opts),
(CheckWindowsFeaturesOptions opts) => Resolve<CheckWindowsFeaturesCommand>().Execute(opts),
(CreateTestProjectOptions opts) => Resolve<CreateTestProjectCommand>(opts).Execute(opts),
(DeactivatePkgOptions opts) => Resolve<DeactivatePackageCommand>(opts).Execute(opts),
_ => 1,
};
};
Expand Down

0 comments on commit b50d799

Please sign in to comment.