Skip to content

Commit

Permalink
separate namespace for new models (#12402)
Browse files Browse the repository at this point in the history
* separate namespace for new models

* tests added
  • Loading branch information
mirkoSekulic authored Feb 28, 2024
1 parent fb00671 commit 923b009
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,17 @@ public JsonMetadataToCsharpConverter(CSharpGenerationSettings generationSettings

private string Indent(int level = 1) => new string(' ', level * _generationSettings.IndentSize);

/// <summary>
/// Create Model from ServiceMetadata object
/// </summary>
/// <param name="serviceMetadata">ServiceMetadata object</param>
/// <returns>The model code in C#</returns>
public string CreateModelFromMetadata(ModelMetadata serviceMetadata)
/// <inheritdoc />
public string CreateModelFromMetadata(ModelMetadata serviceMetadata, bool separateNamespaces = false)
{
Dictionary<string, string> classes = new();

CreateModelFromMetadataRecursive(classes, serviceMetadata.Elements.Values.First(el => el.ParentElement == null), serviceMetadata, serviceMetadata.TargetNamespace);
var rootElementType = serviceMetadata.GetRootElement();
string modelNamespace = _generationSettings.ModelNamespace +
(separateNamespaces ? $".{rootElementType.TypeName}"
: string.Empty);

CreateModelFromMetadataRecursive(classes, rootElementType, serviceMetadata, serviceMetadata.TargetNamespace);

StringBuilder writer = new StringBuilder()
.AppendLine("using System;")
Expand All @@ -41,7 +42,7 @@ public string CreateModelFromMetadata(ModelMetadata serviceMetadata)
.AppendLine("using System.Xml.Serialization;")
.AppendLine("using Microsoft.AspNetCore.Mvc.ModelBinding;")
.AppendLine("using Newtonsoft.Json;")
.AppendLine($"namespace {_generationSettings.ModelNamespace}")
.AppendLine($"namespace {modelNamespace}")
.AppendLine("{")
.Append(string.Concat(classes.Values))
.AppendLine("}");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ public interface IModelMetadataToCsharpConverter
/// Create Model from ServiceMetadata object
/// </summary>
/// <param name="serviceMetadata">ServiceMetadata object</param>
/// <param name="separateNamespaces">Indicates if models should be stored in the separate namespace.</param>
/// <returns>The model code in C#</returns>
public string CreateModelFromMetadata(ModelMetadata serviceMetadata);
public string CreateModelFromMetadata(ModelMetadata serviceMetadata, bool separateNamespaces = false);
}
}
8 changes: 8 additions & 0 deletions backend/src/DataModeling/Metamodel/ModelMetadataExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using System.Linq;

namespace Altinn.Studio.DataModeling.Metamodel;

public static class ModelMetadataExtensions
{
public static ElementMetadata GetRootElement(this ModelMetadata modelMetadata) => modelMetadata.Elements.Values.First(e => e.ParentElement == null);
}
21 changes: 13 additions & 8 deletions backend/src/Designer/Services/Implementation/SchemaModelService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,9 @@ public async Task<string> UpdateModelFilesFromJsonSchema(AltinnRepoEditingContex
string serializedModelMetadata = SerializeModelMetadata(modelMetadata);
await altinnAppGitRepository.SaveModelMetadata(serializedModelMetadata, schemaName);

await UpdateCSharpClasses(altinnAppGitRepository, modelMetadata, schemaName);
string fullTypeName = await UpdateCSharpClasses(altinnAppGitRepository, modelMetadata, schemaName);

await UpdateApplicationMetadata(altinnAppGitRepository, schemaName, modelMetadata.Elements.Values.First(e => e.ParentElement == null).TypeName);
await UpdateApplicationMetadata(altinnAppGitRepository, schemaName, fullTypeName);

return jsonContent;
}
Expand Down Expand Up @@ -294,17 +294,22 @@ private Json.Schema.JsonSchema GenerateJsonSchemaFromXsd(Stream xsdStream)

}

private async Task UpdateCSharpClasses(AltinnAppGitRepository altinnAppGitRepository, ModelMetadata modelMetadata, string schemaName)
private async Task<string> UpdateCSharpClasses(AltinnAppGitRepository altinnAppGitRepository, ModelMetadata modelMetadata, string schemaName)
{
string csharpClasses = _modelMetadataToCsharpConverter.CreateModelFromMetadata(modelMetadata);
ApplicationMetadata application = await altinnAppGitRepository.GetApplicationMetadata();
string modelName = modelMetadata.GetRootElement().TypeName;
bool separateNamespace = !application.DataTypes.Any(d => d.AppLogic?.ClassRef == $"Altinn.App.Models.{modelName}");

string csharpClasses = _modelMetadataToCsharpConverter.CreateModelFromMetadata(modelMetadata, separateNamespace);
await altinnAppGitRepository.SaveCSharpClasses(csharpClasses, schemaName);
return separateNamespace ? $"Altinn.App.Models.{modelName}.{modelName}" : $"Altinn.App.Models.{modelName}";
}

private static async Task UpdateApplicationMetadata(AltinnAppGitRepository altinnAppGitRepository, string schemaName, string typeName)
private static async Task UpdateApplicationMetadata(AltinnAppGitRepository altinnAppGitRepository, string schemaName, string fullTypeName)
{
ApplicationMetadata application = await altinnAppGitRepository.GetApplicationMetadata();

UpdateApplicationWithAppLogicModel(application, schemaName, "Altinn.App.Models." + typeName);
UpdateApplicationWithAppLogicModel(application, schemaName, fullTypeName);

await altinnAppGitRepository.SaveApplicationMetadata(application);
}
Expand Down Expand Up @@ -415,9 +420,9 @@ private async Task<string> ProcessNewXsd(AltinnAppGitRepository altinnAppGitRepo

await altinnAppGitRepository.SaveModelMetadata(serializedModelMetadata, schemaName);

await UpdateCSharpClasses(altinnAppGitRepository, modelMetadata, schemaName);
string fullTypeName = await UpdateCSharpClasses(altinnAppGitRepository, modelMetadata, schemaName);

await UpdateApplicationMetadata(altinnAppGitRepository, schemaName, modelMetadata.Elements.Values.First(e => e.ParentElement == null).TypeName);
await UpdateApplicationMetadata(altinnAppGitRepository, schemaName, fullTypeName);

return jsonContent;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Threading.Tasks;
using Altinn.App.Core.Models;
using Designer.Tests.Controllers.ApiTests;
using Designer.Tests.Utils;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using SharedResources.Tests;
using Xunit;

namespace Designer.Tests.Controllers.DataModelsController;

public class AddXsd_CsharpNamespaceTests : DisagnerEndpointsTestsBase<AddXsd_CsharpNamespaceTests>, IClassFixture<WebApplicationFactory<Program>>
{
private static string VersionPrefix(string org, string repository) => $"/designer/api/{org}/{repository}/datamodels";

public AddXsd_CsharpNamespaceTests(WebApplicationFactory<Program> factory) : base(factory)
{
}

[Theory]
[InlineData("Model/XmlSchema/Gitea/aal-vedlegg.xsd", "ttd", "empty-app", "testUser", "App/models/aal-vedlegg.cs", "Altinn.App.Models.vedlegg", "vedlegg", "Altinn.App.Models")]
[InlineData("Kursdomene_HvemErHvem_M_2021-04-08_5742_34627_SERES.xsd", "ttd", "hvem-er-hvem", "testUser", "App/models/Kursdomene_HvemErHvem_M_2021-04-08_5742_34627_SERES.cs", "Altinn.App.Models", "HvemErHvem_M", "Altinn.App.Models.HvemErHvem_M")]
public async Task GivenApp_ShouldProduce_CorrectNamespace(string xsdPath, string org, string repo, string developer, string expectedModelPath, string expectedNamespace, string expectedTypeName, string notExpectedNamespace)
{
string targetRepository = TestDataHelper.GenerateTestRepoName();
await CopyRepositoryForTest(org, repo, developer, targetRepository);
string url = $"{VersionPrefix(org, targetRepository)}/upload";

var fileStream = SharedResourcesHelper.LoadTestData(xsdPath);
var formData = new MultipartFormDataContent();
var streamContent = new StreamContent(fileStream);
streamContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
formData.Add(streamContent, "file", Path.GetFileName(xsdPath));

using var response = await HttpClient.PostAsync(url, formData);
Assert.Equal(HttpStatusCode.Created, response.StatusCode);

// get the csharp model from repo
string csharpModel = TestDataHelper.GetFileFromRepo(org, targetRepository, developer, expectedModelPath);
csharpModel.Should().Contain($"namespace {expectedNamespace}\n{{");

string applicationMetadataContent = TestDataHelper.GetFileFromRepo(org, targetRepository, developer, "App/config/applicationmetadata.json");
var applicationMetadata = JsonSerializer.Deserialize<ApplicationMetadata>(applicationMetadataContent, JsonSerializerOptions);

applicationMetadata.DataTypes.Should().Contain(x => x.AppLogic != null && x.AppLogic.ClassRef ==
$"{expectedNamespace}.{expectedTypeName}");

applicationMetadata.DataTypes.Should().NotContain(x => x.AppLogic != null && x.AppLogic.ClassRef ==
$"{notExpectedNamespace}.{expectedTypeName}");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System;
using System.Net;
using System.Net.Http;
using System.Net.Mime;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Altinn.App.Core.Models;
using Altinn.Studio.DataModeling.Templates;
using Designer.Tests.Controllers.ApiTests;
using Designer.Tests.Utils;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using Xunit;

namespace Designer.Tests.Controllers.DataModelsController;

public class PutDatamodel_CsharpNamespaceTests : DisagnerEndpointsTestsBase<PutDatamodel_CsharpNamespaceTests>, IClassFixture<WebApplicationFactory<Program>>
{
private static string VersionPrefix(string org, string repository) => $"/designer/api/{org}/{repository}/datamodels";

public PutDatamodel_CsharpNamespaceTests(WebApplicationFactory<Program> factory) : base(factory)
{
}

[Theory]
[InlineData("App/models/Kursdomene_HvemErHvem_M_2021-04-08_5742_34627_SERES.schema.json", "ttd", "hvem-er-hvem", "testUser", "HvemErHvem_M", "App/models/Kursdomene_HvemErHvem_M_2021-04-08_5742_34627_SERES.cs", "Altinn.App.Models", "Altinn.App.Models.HvemErHvem_M")]
[InlineData("App/models/newmodel.schema.json", "ttd", "empty-app", "testUser", "newmodel", "App/models/newmodel.cs", "Altinn.App.Models.newmodel", "Altinn.App.Models")]
public async Task GivenApp_ShouldProduce_CorrectNamespace(string modelPath, string org, string repo, string developer, string expectedModelName, string expectedModelPath, string expectedNamespace, string notExpectedNamespace)
{
string targetRepo = TestDataHelper.GenerateTestRepoName();
await CopyRepositoryForTest(org, repo, developer, targetRepo);
string url = $"{VersionPrefix(org, targetRepo)}/datamodel?modelPath={modelPath}";

string schema = new GeneralJsonTemplate(new Uri("http://altinn-testschema.json"), expectedModelName).GetJsonString();

using var request = new HttpRequestMessage(HttpMethod.Put, url)
{
Content = new StringContent(schema, Encoding.UTF8, MediaTypeNames.Application.Json)
};

using var response = await HttpClient.SendAsync(request);
response.StatusCode.Should().Be(HttpStatusCode.NoContent);
// get the csharp model from repo
string csharpModel = TestDataHelper.GetFileFromRepo(org, targetRepo, developer, expectedModelPath);
csharpModel.Should().Contain($"namespace {expectedNamespace}\n{{");

string applicationMetadataContent = TestDataHelper.GetFileFromRepo(org, targetRepo, developer, "App/config/applicationmetadata.json");
var applicationMetadata = JsonSerializer.Deserialize<ApplicationMetadata>(applicationMetadataContent, JsonSerializerOptions);

applicationMetadata.DataTypes.Should().Contain(x => x.AppLogic != null && x.AppLogic.ClassRef ==
$"{expectedNamespace}.{expectedModelName}");

applicationMetadata.DataTypes.Should().NotContain(x => x.AppLogic != null && x.AppLogic.ClassRef ==
$"{notExpectedNamespace}.{expectedModelName}");
}
}

0 comments on commit 923b009

Please sign in to comment.