Skip to content

Commit 978411f

Browse files
committed
Removal of Cocona and unit tests for new desing
1 parent 6827c9b commit 978411f

File tree

11 files changed

+150
-104
lines changed

11 files changed

+150
-104
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
using Dataverse.ConfigurationMigrationTool.Console.Features;
2+
using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
3+
using Dataverse.ConfigurationMigrationTool.Console.Tests.Extensions;
4+
using Microsoft.Extensions.DependencyInjection;
5+
using Microsoft.Extensions.Hosting;
6+
using Microsoft.Extensions.Logging;
7+
using Microsoft.Extensions.Options;
8+
using NSubstitute;
9+
using Shouldly;
10+
using System.Reflection;
11+
12+
namespace Dataverse.ConfigurationMigrationTool.Console.Tests.Features;
13+
public class CommandProcessorHostingServiceTests
14+
{
15+
private readonly IOptions<CommandProcessorHostingServiceOptions> _options;
16+
private readonly IServiceScopeFactory _serviceProviderFactory;
17+
private readonly IHostApplicationLifetime _lifetime;
18+
private readonly IServiceScope _serviceScope;
19+
private readonly IServiceCollection ServiceCollection = new ServiceCollection();
20+
private readonly ILogger<FakeCommand> commandLogger = Substitute.For<ILogger<FakeCommand>>();
21+
private readonly CommandProcessorHostingServiceOptions HostingOptions = new CommandProcessorHostingServiceOptions
22+
{
23+
CommandVerb = "fake"
24+
};
25+
26+
public CommandProcessorHostingServiceTests()
27+
{
28+
29+
ServiceCollection.AddSingleton<ILogger<FakeCommand>>(commandLogger);
30+
_serviceScope = Substitute.For<IServiceScope>();
31+
_serviceScope.ServiceProvider.Returns(ServiceCollection.BuildServiceProvider());
32+
_options = Substitute.For<IOptions<CommandProcessorHostingServiceOptions>>();
33+
_options.Value.Returns(HostingOptions);
34+
_serviceProviderFactory = Substitute.For<IServiceScopeFactory>();
35+
_serviceProviderFactory.CreateScope().Returns(_serviceScope);
36+
_lifetime = Substitute.For<IHostApplicationLifetime>();
37+
38+
}
39+
40+
[Fact]
41+
public async Task GivenACommandVerb_WhenCommandProcessorRuns_ThenItShouldExecuteTheProperCommand()
42+
{
43+
//Arrange
44+
45+
var host = new CommandProcessorHostingService(_options, _serviceProviderFactory, _lifetime, Assembly.GetExecutingAssembly());
46+
//Act
47+
await host.StartAsync(CancellationToken.None);
48+
49+
//Assert
50+
commandLogger.ShouldHaveLogged(LogLevel.Information, "Fake command executed successfully.");
51+
52+
}
53+
54+
[Fact]
55+
public async Task GivenAnNonExistantCommandVerb_WhenCommandProcessorRuns_ThenItShouldExecuteTheProperCommand()
56+
{
57+
//Arrange
58+
var host = new CommandProcessorHostingService(_options, _serviceProviderFactory, _lifetime);
59+
//Act
60+
Func<Task> act = () => host.StartAsync(CancellationToken.None);
61+
62+
//Assert
63+
var ex = await act.ShouldThrowAsync<InvalidOperationException>();
64+
ex.Message.ShouldBe($"No command found for verb '{HostingOptions.CommandVerb}'");
65+
66+
}
67+
68+
69+
70+
}
71+
[CommandVerb("fake")]
72+
public class FakeCommand : ICommand
73+
{
74+
private readonly ILogger<FakeCommand> _logger;
75+
76+
public FakeCommand(ILogger<FakeCommand> logger)
77+
{
78+
_logger = logger;
79+
}
80+
81+
public Task Execute()
82+
{
83+
_logger.LogInformation("Fake command executed successfully.");
84+
return Task.CompletedTask;
85+
}
86+
}

src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/CoconaAppExtensionsTests.cs

Lines changed: 0 additions & 20 deletions
This file was deleted.

src/Dataverse.ConfigurationMigrationTool/Console.Tests/Features/Import/Commands/ImportCommandsTest.cs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public async Task GivenDataToImportWithSchema_WhenTheCommandExecutes_ThenItShoul
6868
_importDataProvider.ReadSchemaFromFile(SchemaFilePath).Returns(importSchema);
6969
_schemaValidator.Validate(importSchema).Returns(new ValidationResult());
7070
//Act
71-
await _importCommands.Import(SchemaFilePath, DataFilePath);
71+
await _importCommands.Execute();
7272

7373
//Assert
7474
Received.InOrder(async () =>
@@ -79,6 +79,44 @@ public async Task GivenDataToImportWithSchema_WhenTheCommandExecutes_ThenItShoul
7979
await _importDataService.Execute(Arg.Is<ImportDataTask>(x => x.RelationshipSchema == FakeSchemas.Contact.Relationships.Relationship.First()), datasets);
8080
});
8181

82+
}
83+
[Fact]
84+
public async Task GivenDataToImportWithSchema_WhenTheCommandExecutesAndFails_ThenItShouldThrowAnError()
85+
{
86+
//Arrange
87+
var importSchema = new ImportSchema
88+
{
89+
Entity = new()
90+
{
91+
FakeSchemas.Account,
92+
FakeSchemas.Contact,
93+
FakeSchemas.Opportunity
94+
95+
}
96+
};
97+
var datasets = new Entities
98+
{
99+
Entity = new()
100+
{
101+
FakeDatasets.AccountSets,
102+
FakeDatasets.ContactSets,
103+
FakeDatasets.OpportunitiesSet
104+
}
105+
};
106+
_importDataService.Execute(Arg.Any<ImportDataTask>(), Arg.Any<Entities>())
107+
.Returns(TaskResult.Failed);
108+
_importDataProvider.ReadFromFile(DataFilePath).Returns(datasets);
109+
_importDataProvider.ReadSchemaFromFile(SchemaFilePath).Returns(importSchema);
110+
_schemaValidator.Validate(importSchema).Returns(new ValidationResult());
111+
//Act
112+
Func<Task> act = () => _importCommands.Execute();
113+
114+
//Assert
115+
var ex = await act.ShouldThrowAsync<Exception>();
116+
ex.Message.ShouldBe("Import process failed.");
117+
118+
119+
82120
}
83121
[Fact]
84122
public async Task GivenAnInvalidSchema_WhenTheCommandExecutes_ThenItShouldFailAndLogIssues()
@@ -115,7 +153,7 @@ public async Task GivenAnInvalidSchema_WhenTheCommandExecutes_ThenItShouldFailAn
115153
}
116154
});
117155
//Act
118-
Func<Task> act = () => _importCommands.Import(SchemaFilePath, DataFilePath);
156+
Func<Task> act = () => _importCommands.Execute();
119157

120158
//Assert
121159
var ex = await act.ShouldThrowAsync<Exception>();

src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Dataverse.ConfigurationMigrationTool.Console.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010
</PropertyGroup>
1111

1212
<ItemGroup>
13-
<PackageReference Include="Cocona" Version="2.2.0" />
14-
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.4" />
13+
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" Version="9.0.7" />
14+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.7" />
15+
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.7" />
1516
<PackageReference Include="Microsoft.PowerPlatform.Dataverse.Client" Version="1.2.7" />
1617
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" />
17-
<PackageReference Include="System.CommandLine" Version="2.0.0-beta6.25358.103" />
1818
</ItemGroup>
1919
<ItemGroup>
2020
<None Update="appsettings.Development.json">
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,28 @@
1-
using Microsoft.Extensions.DependencyInjection;
1+
using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
2+
using Microsoft.Extensions.DependencyInjection;
23
using Microsoft.Extensions.Hosting;
34
using Microsoft.Extensions.Options;
45
using System.Reflection;
56

6-
namespace Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
7+
namespace Dataverse.ConfigurationMigrationTool.Console.Features;
78
public class CommandProcessorHostingService : BackgroundService
89
{
910
private readonly CommandProcessorHostingServiceOptions _options;
1011
private readonly IServiceScopeFactory _serviceProviderFactory;
1112
private readonly IHostApplicationLifetime _lifetime;
13+
private readonly IEnumerable<Assembly> _commandAssemblies;
1214

13-
public CommandProcessorHostingService(IOptions<CommandProcessorHostingServiceOptions> options, IServiceScopeFactory serviceProviderFactory, IHostApplicationLifetime lifetime)
15+
public CommandProcessorHostingService(IOptions<CommandProcessorHostingServiceOptions> options, IServiceScopeFactory serviceProviderFactory, IHostApplicationLifetime lifetime, params Assembly[] commandAssemblies)
1416
{
1517
_options = options.Value;
1618
_serviceProviderFactory = serviceProviderFactory;
1719
_lifetime = lifetime;
20+
_commandAssemblies = commandAssemblies.Length > 0 ? commandAssemblies : new[] { Assembly.GetExecutingAssembly() };
1821
}
1922

2023
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
2124
{
22-
var types = from type in Assembly.GetExecutingAssembly().GetTypes()
25+
var types = from type in _commandAssemblies.SelectMany(a => a.GetTypes())
2326
where Attribute.IsDefined(type, typeof(CommandVerbAttribute)) &&
2427
type.IsClass &&
2528
!type.IsAbstract &&
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
namespace Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
1+
namespace Dataverse.ConfigurationMigrationTool.Console.Features;
22
public class CommandProcessorHostingServiceOptions
33
{
44
public string CommandVerb { get; set; }

src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/CoconaAppExtensions.cs

Lines changed: 0 additions & 15 deletions
This file was deleted.

src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Features/Import/Commands/ImportCommands.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
using Cocona;
2-
using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
1+
using Dataverse.ConfigurationMigrationTool.Console.Features.Import.Model;
32
using Dataverse.ConfigurationMigrationTool.Console.Features.Shared;
43
using Microsoft.Extensions.Logging;
54
using Microsoft.Extensions.Options;
6-
using ConsoleApp = System.Console;
75

86
namespace Dataverse.ConfigurationMigrationTool.Console.Features.Import.Commands;
97
[CommandVerb("import")]
@@ -31,15 +29,12 @@ public ImportCommands(ILogger<ImportCommands> logger,
3129
public async Task Execute() => await Import(_options.schema, _options.data);
3230

3331

34-
[Command("import")]
35-
public async Task Import([Option("schema")] string schemafilepath, [Option("data")] string datafilepath)
32+
private async Task Import(string schemafilepath, string datafilepath)
3633
{
3734

3835
var ImportQueue = new Queue<ImportDataTask>();
39-
ConsoleApp.WriteLine($"{datafilepath} with schema {schemafilepath}");
4036
var schema = await _importDataProvider.ReadSchemaFromFile(schemafilepath);
4137
var importdata = await _importDataProvider.ReadFromFile(datafilepath);
42-
ConsoleApp.WriteLine($"Schema Count: {schema.Entity.Count} | Data count {importdata.Entity.Count}");
4338

4439

4540
var schemaValidationResult = await _schemaValidator.Validate(schema);
@@ -66,7 +61,7 @@ public async Task Import([Option("schema")] string schemafilepath, [Option("data
6661
}
6762
}
6863

69-
64+
var taskResults = new List<TaskResult>();
7065
while (ImportQueue.Count > 0)
7166
{
7267
var importTask = ImportQueue.Dequeue();
@@ -90,11 +85,16 @@ public async Task Import([Option("schema")] string schemafilepath, [Option("data
9085
}
9186
#endregion
9287

93-
await _importDataService.Execute(importTask, importdata);
94-
88+
var result = await _importDataService.Execute(importTask, importdata);
89+
taskResults.Add(result);
9590

9691

9792
}
93+
if (taskResults.Any(r => r == TaskResult.Failed))
94+
{
95+
_logger.LogError("Import process failed.");
96+
throw new Exception("Import process failed.");
97+
}
9898

9999

100100

src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Program.cs

Lines changed: 2 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
using Microsoft.Extensions.Logging;
1111
using Microsoft.PowerPlatform.Dataverse.Client;
1212
using System.Reflection;
13-
var builder = new HostBuilder();
13+
var builder = Host.CreateDefaultBuilder(args);
1414
builder.ConfigureHostConfiguration((config) =>
1515
{
1616
// Configure the host configuration, such as environment variables, command line arguments, etc.
@@ -33,10 +33,6 @@
3333
config.AddUserSecrets(Assembly.GetExecutingAssembly());
3434
}
3535
Console.WriteLine($"Using configuration file: appsettings.{context.HostingEnvironment.EnvironmentName}.json");
36-
foreach (var arg in context.Configuration.AsEnumerable())
37-
{
38-
Console.WriteLine($"Configuration: {arg.Key} => {arg.Value}");
39-
}
4036
});
4137
builder.ConfigureServices((context, services) =>
4238
{
@@ -56,44 +52,6 @@
5652
.AddImportFeature(context.Configuration);
5753
// Configure other services.
5854
});
59-
builder.ConfigureCocona(args, configureApplication: app =>
60-
{
61-
// Configure your app's commands normally as you would with app
62-
app.UseImportFeature();
63-
});
55+
6456
var app = builder.Build();
6557
await app.RunAsync();
66-
//var builder = CoconaApp.CreateBuilder();
67-
//builder.Configuration
68-
// .AddEnvironmentVariables()
69-
// .AddJsonFile("appsettings.json", false, false)
70-
// .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", false, false);
71-
//Console.WriteLine($"Using configuration file: appsettings.{builder.Environment.EnvironmentName}.json");
72-
//foreach (var arg in args)
73-
//{
74-
// Console.WriteLine($"Argument: {arg}");
75-
//}
76-
//if (!builder.Environment.IsProduction())
77-
//{
78-
// //Secrets should never be in clear text in source controlled file such appsettings.json.
79-
// //For Developement, we therefore store them locally into UserSecrets Store, part of dotnet foundation.
80-
// //For Production, secrets can be either written into appsettings.Production.json file by pipeline
81-
// //or you can configure another Configuration Provider to provide the secrets like AzureKeyvault or Hashicorp Vault.
82-
// builder.Configuration.AddUserSecrets(Assembly.GetExecutingAssembly());
83-
//}
84-
//builder.Services
85-
// .AddLogging(lb => lb.AddConsole())
86-
// .Configure<SdkDataverseServiceFactoryOptions>(builder.Configuration.GetSection("Dataverse"))
87-
// .Configure<ParallelismBulkOrganizationServiceOptions>(builder.Configuration.GetSection("Dataverse"))
88-
// .AddTransient<IImportDataProvider, FileReaderDataImportProvider>()
89-
// .AddSingleton<IFileDataReader, XmlFileDataReader>()
90-
// .AddTransient<IMetadataService, DataverseMetadataService>()
91-
// .AddTransient<ServiceClient>((sp) => (ServiceClient)sp.GetRequiredService<IDataverseClientFactory>().Create())
92-
// .AddSingleton<IBulkOrganizationService, ParallelismBulkOrganizationService>()
93-
// .AddDataverseClient()
94-
// .AddImportFeature();
95-
//Console.WriteLine($"Services are completed");
96-
//var app = builder.Build();
97-
//app.UseImportFeature();
98-
//Console.WriteLine($"Running App");
99-
//await app.RunAsync();

src/Dataverse.ConfigurationMigrationTool/Dataverse.ConfigurationMigrationTool.Console/Services/Dataverse/SdkDataverseServiceFactory.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,6 @@ public SdkDataverseServiceFactory(IOptions<SdkDataverseServiceFactoryOptions> op
1818
}
1919
public IOrganizationServiceAsync2 Create()
2020
{
21-
_logger.LogInformation("ClientId Length", _options.ClientId.ToString().Length);
22-
_logger.LogInformation("ClientSecret Length", _options.ClientSecret.ToString().Length);
23-
_logger.LogInformation("Url Length", _options.Url.ToString().Length);
24-
// throw new InvalidOperationException($"test: {_options.Url} {_options.ClientId} {_options.ClientSecret}");
2521
var serviceClient = new ServiceClient(
2622
new Uri(_options.Url),
2723
_options.ClientId.ToString(),

0 commit comments

Comments
 (0)