diff --git a/src/Altinn.App.Api/Controllers/ActionsController.cs b/src/Altinn.App.Api/Controllers/ActionsController.cs index 2786ee59b..a31b92941 100644 --- a/src/Altinn.App.Api/Controllers/ActionsController.cs +++ b/src/Altinn.App.Api/Controllers/ActionsController.cs @@ -213,10 +213,9 @@ await Task.WhenAll( ); await saveTask; - var updatedDataModels = changes.FormDataChanges.ToDictionary( - c => c.DataElementIdentifier.Id, - c => c.CurrentFormData - ); + var updatedDataModels = changes + .FormDataChanges.Where(c => c.Type != ChangeType.Deleted) + .ToDictionary(c => c.DataElementIdentifier.Id, c => c.CurrentFormData); return Ok( new UserActionResponse() diff --git a/src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs b/src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs index 36744dacf..cab697cc2 100644 --- a/src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs +++ b/src/Altinn.App.Core/Internal/Data/InstanceDataUnitOfWork.cs @@ -147,7 +147,7 @@ public FormDataChange AddFormDataElement(string dataTypeId, object model) if (modelType.FullName != classRef) { throw new InvalidOperationException( - $"Data object registered for {dataTypeId} is not of type {classRef} as specified in application metadata" + $"Tried to save {modelType.FullName} as {dataTypeId}, but applicationmetadata.json specifies {classRef}" ); } diff --git a/src/Altinn.App.Core/Models/UserAction/UserActionContext.cs b/src/Altinn.App.Core/Models/UserAction/UserActionContext.cs index d2caf7c64..441548ab7 100644 --- a/src/Altinn.App.Core/Models/UserAction/UserActionContext.cs +++ b/src/Altinn.App.Core/Models/UserAction/UserActionContext.cs @@ -66,7 +66,7 @@ public UserActionContext( /// /// Access dataElements through this accessor to ensure that changes gets saved in storage and returned to frontend /// - public IInstanceDataAccessor DataMutator { get; } + public IInstanceDataMutator DataMutator { get; } /// /// The user performing the action diff --git a/test/Altinn.App.Api.Tests/Controllers/ActionsControllerTests.cs b/test/Altinn.App.Api.Tests/Controllers/ActionsControllerTests.cs index 28a18fd44..1ed3f22e7 100644 --- a/test/Altinn.App.Api.Tests/Controllers/ActionsControllerTests.cs +++ b/test/Altinn.App.Api.Tests/Controllers/ActionsControllerTests.cs @@ -1,16 +1,20 @@ using System.Net; using System.Net.Http.Headers; +using System.Net.Http.Json; using System.Text; using System.Text.Json; using Altinn.App.Api.Models; using Altinn.App.Api.Tests.Data; +using Altinn.App.Api.Tests.Data.apps.tdd.task_action.config.models; using Altinn.App.Api.Tests.Utils; using Altinn.App.Core.Features; +using Altinn.App.Core.Internal.Data; using Altinn.App.Core.Models.Process; using Altinn.App.Core.Models.UserAction; using FluentAssertions; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; using Xunit.Abstractions; namespace Altinn.App.Api.Tests.Controllers; @@ -35,7 +39,6 @@ public async Task Perform_returns_403_if_user_not_authorized() var app = "task-action"; HttpClient client = GetRootedClient(org, app); Guid guid = new Guid("b1135209-628e-4a6e-9efd-e4282068ef41"); - TestData.DeleteInstanceAndData(org, app, 1337, guid); TestData.PrepareInstance(org, app, 1337, guid); string token = PrincipalUtil.GetToken(1000, null, 3); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); @@ -61,7 +64,6 @@ public async Task Perform_returns_401_if_user_not_authenticated() var app = "task-action"; HttpClient client = GetRootedClient(org, app); Guid guid = new Guid("b1135209-628e-4a6e-9efd-e4282068ef41"); - TestData.DeleteInstanceAndData(org, app, 1337, guid); TestData.PrepareInstance(org, app, 1337, guid); using var content = new StringContent( "{\"action\":\"lookup_unauthorized\"}", @@ -85,7 +87,6 @@ public async Task Perform_returns_401_if_userId_is_null() var app = "task-action"; HttpClient client = GetRootedClient(org, app); Guid guid = new Guid("b1135209-628e-4a6e-9efd-e4282068ef41"); - TestData.DeleteInstanceAndData(org, app, 1337, guid); TestData.PrepareInstance(org, app, 1337, guid); string token = PrincipalUtil.GetToken(null, null, 3); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); @@ -111,7 +112,6 @@ public async Task Perform_returns_400_if_action_is_null() var app = "task-action"; HttpClient client = GetRootedClient(org, app); Guid guid = new Guid("b1135209-628e-4a6e-9efd-e4282068ef41"); - TestData.DeleteInstanceAndData(org, app, 1337, guid); TestData.PrepareInstance(org, app, 1337, guid); string token = PrincipalUtil.GetToken(1000, null, 3); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); @@ -133,7 +133,6 @@ public async Task Perform_returns_409_if_process_not_started() var app = "task-action"; HttpClient client = GetRootedClient(org, app); Guid guid = new Guid("b1135209-628e-4a6e-9efd-e4282068ef43"); - TestData.DeleteInstanceAndData(org, app, 1337, guid); TestData.PrepareInstance(org, app, 1337, guid); string token = PrincipalUtil.GetToken(1000, null, 3); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); @@ -155,7 +154,6 @@ public async Task Perform_returns_409_if_process_ended() var app = "task-action"; HttpClient client = GetRootedClient(org, app); Guid guid = new Guid("b1135209-628e-4a6e-9efd-e4282068ef42"); - TestData.DeleteInstanceAndData(org, app, 1337, guid); TestData.PrepareInstance(org, app, 1337, guid); string token = PrincipalUtil.GetToken(1000, null, 3); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); @@ -181,7 +179,6 @@ public async Task Perform_returns_200_if_action_succeeded() var app = "task-action"; HttpClient client = GetRootedClient(org, app); Guid guid = new Guid("b1135209-628e-4a6e-9efd-e4282068ef41"); - TestData.DeleteInstanceAndData(org, app, 1337, guid); TestData.PrepareInstance(org, app, 1337, guid); string token = PrincipalUtil.GetToken(1000, null, 3); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); @@ -234,7 +231,6 @@ public async Task Perform_returns_400_if_action_failed_and_errorType_is_BadReque var app = "task-action"; HttpClient client = GetRootedClient(org, app); Guid guid = new Guid("b1135209-628e-4a6e-9efd-e4282068ef41"); - TestData.DeleteInstanceAndData(org, app, 1337, guid); TestData.PrepareInstance(org, app, 1337, guid); string token = PrincipalUtil.GetToken(400, null, 3); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); @@ -260,7 +256,6 @@ public async Task Perform_returns_401_if_action_failed_and_errorType_is_Unauthor var app = "task-action"; HttpClient client = GetRootedClient(org, app); Guid guid = new Guid("b1135209-628e-4a6e-9efd-e4282068ef41"); - TestData.DeleteInstanceAndData(org, app, 1337, guid); TestData.PrepareInstance(org, app, 1337, guid); string token = PrincipalUtil.GetToken(401, null, 3); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); @@ -286,7 +281,6 @@ public async Task Perform_returns_409_if_action_failed_and_errorType_is_Conflict var app = "task-action"; HttpClient client = GetRootedClient(org, app); Guid guid = new Guid("b1135209-628e-4a6e-9efd-e4282068ef41"); - TestData.DeleteInstanceAndData(org, app, 1337, guid); TestData.PrepareInstance(org, app, 1337, guid); string token = PrincipalUtil.GetToken(409, null, 3); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); @@ -312,7 +306,6 @@ public async Task Perform_returns_500_if_action_failed_and_errorType_is_Internal var app = "task-action"; HttpClient client = GetRootedClient(org, app); Guid guid = new Guid("b1135209-628e-4a6e-9efd-e4282068ef41"); - TestData.DeleteInstanceAndData(org, app, 1337, guid); TestData.PrepareInstance(org, app, 1337, guid); string token = PrincipalUtil.GetToken(500, null, 3); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); @@ -338,7 +331,6 @@ public async Task Perform_returns_404_if_action_implementation_not_found() var app = "task-action"; HttpClient client = GetRootedClient(org, app); Guid guid = new Guid("b1135209-628e-4a6e-9efd-e4282068ef41"); - TestData.DeleteInstanceAndData(org, app, 1337, guid); TestData.PrepareInstance(org, app, 1337, guid); string token = PrincipalUtil.GetToken(1001, null, 3); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); @@ -353,6 +345,197 @@ public async Task Perform_returns_404_if_action_implementation_not_found() response.StatusCode.Should().Be(HttpStatusCode.NotFound); } + [Fact] + public async Task PerformFillActionThatMutatesData() + { + var org = "tdd"; + var app = "task-action"; + Guid instanceGuid = new Guid("b1135209-628e-4a6e-9efd-e4282068ef41"); + int instanceOwner = 1337; + TestData.PrepareInstance(org, app, 1337, instanceGuid); + OverrideServicesForThisTest = (services) => + { + services.AddTransient(); + }; + var client = GetRootedClient(org, app, 1337, null); + string token = PrincipalUtil.GetToken(1001, null, 3); + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); + + // Run buttonId "add" + using var content = JsonContent.Create(new { action = "fill", buttonId = "add" }); + using HttpResponseMessage addResponse = await client.PostAsync( + $"/{org}/{app}/instances/{instanceOwner}/{instanceGuid}/actions", + content + ); + + var parsedAddResponse = await VerifyStatusAndDeserialize(addResponse, HttpStatusCode.OK); + parsedAddResponse.ClientActions.Should().BeEmpty(); + parsedAddResponse.Instance.Should().NotBeNull(); + parsedAddResponse.Instance.Id.Should().Be($"{instanceOwner}/{instanceGuid}"); + var dataElement = parsedAddResponse.Instance.Data.Should().ContainSingle().Which; + + var schemeElement = parsedAddResponse + .UpdatedDataModels.Should() + .HaveCount(1) + .And.ContainKey(dataElement.Id) + .WhoseValue.Should() + .BeOfType() + .Which; + var scheme = + schemeElement.Deserialize(_jsonSerializerOptions) + ?? throw new Exception("Failed to deserialize Scheme"); + scheme.TestCustomButtonInput.Should().Be("Hello a"); + + // Run buttonId "update" + using var updateContent = JsonContent.Create(new { action = "fill", buttonId = "update" }); + using HttpResponseMessage updateResponse = await client.PostAsync( + $"/{org}/{app}/instances/{instanceOwner}/{instanceGuid}/actions", + updateContent + ); + var parsedUpdateResponse = await VerifyStatusAndDeserialize( + updateResponse, + HttpStatusCode.OK + ); + parsedUpdateResponse.ClientActions.Should().BeEmpty(); + parsedUpdateResponse.Instance.Should().NotBeNull(); + parsedUpdateResponse.Instance.Id.Should().Be($"{instanceOwner}/{instanceGuid}"); + var updatedDataElement = parsedUpdateResponse.Instance.Data.Should().ContainSingle().Which; + var updatedSchemeElement = parsedUpdateResponse + .UpdatedDataModels.Should() + .HaveCount(1) + .And.ContainKey(updatedDataElement.Id) + .WhoseValue.Should() + .BeOfType() + .Which; + var updatedScheme = + updatedSchemeElement.Deserialize(_jsonSerializerOptions) + ?? throw new Exception("Failed to deserialize Scheme"); + updatedScheme.TestCustomButtonInput.Should().Be("Hello a"); + updatedScheme.TestCustomButtonReadOnlyInput.Should().Be("Her kommer det data fra backend"); + + TestData + .GetDataElementBlobContnet(org, app, instanceOwner, instanceGuid, Guid.Parse(updatedDataElement.Id)) + .Should() + .Contain("Her kommer det data fra backend"); + + // Run buttonId "updateObsolete" + using var updateObsoleteContent = JsonContent.Create(new { action = "fill", buttonId = "updateObsolete" }); + using HttpResponseMessage updateObsoleteResponse = await client.PostAsync( + $"/{org}/{app}/instances/{instanceOwner}/{instanceGuid}/actions", + updateObsoleteContent + ); + var parsedUpdateObsoleteResponse = await VerifyStatusAndDeserialize( + updateObsoleteResponse, + HttpStatusCode.OK + ); + parsedUpdateObsoleteResponse.ClientActions.Should().BeEmpty(); + parsedUpdateObsoleteResponse.Instance.Should().NotBeNull(); + parsedUpdateObsoleteResponse.Instance.Id.Should().Be($"{instanceOwner}/{instanceGuid}"); + var updatedObsoleteDataElement = parsedUpdateObsoleteResponse.Instance.Data.Should().ContainSingle().Which; + var updatedObsoleteSchemeElement = parsedUpdateObsoleteResponse + .UpdatedDataModels.Should() + .HaveCount(1) + .And.ContainKey(updatedObsoleteDataElement.Id) + .WhoseValue.Should() + .BeOfType() + .Which; + var updatedObsoleteScheme = + updatedObsoleteSchemeElement.Deserialize(_jsonSerializerOptions) + ?? throw new Exception("Failed to deserialize Scheme"); + updatedObsoleteScheme.description.Should().Be("Obsolete data"); + + TestData + .GetDataElementBlobContnet(org, app, instanceOwner, instanceGuid, Guid.Parse(updatedDataElement.Id)) + .Should() + .Contain("Obsolete data"); + + // Run buttonId "delete" + using var deleteContent = JsonContent.Create(new { action = "fill", buttonId = "delete" }); + using HttpResponseMessage deleteResponse = await client.PostAsync( + $"/{org}/{app}/instances/{instanceOwner}/{instanceGuid}/actions", + deleteContent + ); + var parsedDeleteResponse = await VerifyStatusAndDeserialize( + deleteResponse, + HttpStatusCode.OK + ); + parsedDeleteResponse.ClientActions.Should().BeEmpty(); + parsedDeleteResponse.Instance.Should().NotBeNull(); + parsedDeleteResponse.Instance.Id.Should().Be($"{instanceOwner}/{instanceGuid}"); + parsedDeleteResponse.Instance.Data.Should().BeEmpty(); + parsedDeleteResponse.UpdatedDataModels.Should().BeEmpty(); + + // Cleanup testdata + TestData.DeleteInstanceAndData(org, app, instanceOwner, instanceGuid); + } + + [Fact] + public async Task PerformFillAction_GetClientActions() + { + var org = "tdd"; + var app = "task-action"; + Guid instanceGuid = new Guid("b1135209-628e-4a6e-9efd-e4282068ef41"); + int instanceOwner = 1337; + TestData.PrepareInstance(org, app, 1337, instanceGuid); + OverrideServicesForThisTest = (services) => + { + services.AddTransient(); + }; + var client = GetRootedClient(org, app, 1337, null); + string token = PrincipalUtil.GetToken(1001, null, 3); + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); + + // run buttonId "getClientActions" + using var getClientActionsContent = JsonContent.Create(new { action = "fill", buttonId = "getClientActions" }); + using HttpResponseMessage getClientActionsResponse = await client.PostAsync( + $"/{org}/{app}/instances/{instanceOwner}/{instanceGuid}/actions", + getClientActionsContent + ); + var parsedGetClientActionsResponse = await VerifyStatusAndDeserialize( + getClientActionsResponse, + HttpStatusCode.OK + ); + parsedGetClientActionsResponse.ClientActions.Should().ContainSingle().Which.Id.Should().Be("nextPage"); + + // Cleanup testdata + TestData.DeleteInstanceAndData(org, app, instanceOwner, instanceGuid); + } + + [Fact] + public async Task PerformFillAction_Fail() + { + var org = "tdd"; + var app = "task-action"; + Guid instanceGuid = new Guid("b1135209-628e-4a6e-9efd-e4282068ef41"); + int instanceOwner = 1337; + TestData.PrepareInstance(org, app, 1337, instanceGuid); + OverrideServicesForThisTest = (services) => + { + services.AddTransient(); + }; + var client = GetRootedClient(org, app, 1337, null); + string token = PrincipalUtil.GetToken(1001, null, 3); + client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); + + // Run buttonId "fail" + using var failContent = JsonContent.Create(new { action = "fill", buttonId = "fail" }); + using HttpResponseMessage failResponse = await client.PostAsync( + $"/{org}/{app}/instances/{instanceOwner}/{instanceGuid}/actions", + failContent + ); + var parsedFailResponse = await VerifyStatusAndDeserialize( + failResponse, + HttpStatusCode.Conflict + ); + parsedFailResponse.ClientActions.Should().ContainSingle().Which.Id.Should().Be("nextPage"); + parsedFailResponse.Error.Should().NotBeNull(); + parsedFailResponse.Error!.Code.Should().Be("machine-readable-error-code"); + parsedFailResponse.Error!.Message.Should().Be("Her kommer det en feilmelding"); + + // Cleanup testdata + TestData.DeleteInstanceAndData(org, app, instanceOwner, instanceGuid); + } + //TODO: replace this assertion with a proper one once fluentassertions has a json compare feature scheduled for v7 https://github.com/fluentassertions/fluentassertions/issues/2205 private void CompareResult(string expectedString, string actualString, Action? mutator = null) { @@ -366,6 +549,88 @@ private void CompareResult(string expectedString, string actualString, Action } } +public class FillAction : IUserAction +{ + private readonly ILogger _logger; + private readonly IDataClient _dataClient; + + public string Id => "fill"; + + public FillAction(ILogger logger, IDataClient dataClient) + { + _logger = logger; + _dataClient = dataClient; + } + + public async Task HandleAction(UserActionContext context) + { + _logger.LogInformation("FillAction triggered, with button id: {buttonId}", context.ButtonId); + + switch (context.ButtonId) + { + case "add": + context.DataMutator.AddFormDataElement( + "Scheme", + new Scheme() + { + TestCustomButtonReadOnlyInput = "Første runde", + TestCustomButtonInput = "Hello a", + description = "Første runde" + } + ); + break; + case "update": + var originalDataElement = context.DataMutator.FormDataElements.First(de => de.DataType == "Scheme"); + var originalData = await context.DataMutator.GetFormData(originalDataElement); + var data = (Scheme)originalData; + + data.TestCustomButtonReadOnlyInput = "Her kommer det data fra backend"; + break; + case "updateObsolete": + var instanceId = context.Instance.Id; + var instanceGuid = Guid.Parse(instanceId.Split('/')[1]); + var instanceOwner = int.Parse(instanceId.Split('/')[0]); + var dataGuid = Guid.Parse(context.Instance.Data.Single().Id); + + var obsoleteData = (Scheme) + await _dataClient.GetFormData( + instanceGuid, + typeof(Scheme), + context.Instance.Org, + context.Instance.AppId.Split('/')[1], + instanceOwner, + dataGuid + ); + obsoleteData.description = "Obsolete data"; + var result = UserActionResult.SuccessResult(new List()); + result.AddUpdatedDataModel(dataGuid.ToString(), obsoleteData); + return result; + case "delete": + var elementToDelete = context.DataMutator.FormDataElements.First(de => de.DataType == "Scheme"); + context.DataMutator.RemoveDataElement(elementToDelete); + break; + case "getClientActions": + return UserActionResult.SuccessResult([new ClientAction() { Id = "nextPage" }]); + + case "fail": + return UserActionResult.FailureResult( + new ActionError() + { + Code = "machine-readable-error-code", + Message = "Her kommer det en feilmelding", + Metadata = new Dictionary() { { "key1", "value1" }, } + }, + [new ClientAction() { Id = "nextPage" }], + errorType: ProcessErrorType.Conflict + ); + default: + throw new Exception($"Button id {context.ButtonId} not supported"); + } + + return UserActionResult.SuccessResult(new List()); + } +} + public class LookupAction : IUserAction { public string Id => "lookup"; diff --git a/test/Altinn.App.Api.Tests/Controllers/DataControllerTests.cs b/test/Altinn.App.Api.Tests/Controllers/DataControllerTests.cs index ca16fa3f5..c19e18e03 100644 --- a/test/Altinn.App.Api.Tests/Controllers/DataControllerTests.cs +++ b/test/Altinn.App.Api.Tests/Controllers/DataControllerTests.cs @@ -30,7 +30,6 @@ public async Task PutDataElement_MissingDataType_ReturnsBadRequest() string token = PrincipalUtil.GetOrgToken("nav", "160694123"); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); - TestData.DeleteInstanceAndData(org, app, instanceOwnerPartyId, guid); TestData.PrepareInstance(org, app, instanceOwnerPartyId, guid); using var content = new StringContent("{}", System.Text.Encoding.UTF8, "application/json"); // empty valid json @@ -53,7 +52,6 @@ public async Task PostBinaryElement_ContentTooLarge_ReturnsBadRequest() string token = PrincipalUtil.GetOrgToken("nav", "160694123"); client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); - TestData.DeleteInstanceAndData(org, app, instanceOwnerPartyId, guid); TestData.PrepareInstance(org, app, instanceOwnerPartyId, guid); using var content = new ByteArrayContent(new byte[1024 * 1024 + 1]); // 1 mb @@ -93,7 +91,6 @@ public async Task CreateDataElement_BinaryPdf_AnalyserShouldRunOk() HttpClient client = GetRootedClient(org, app); Guid guid = new Guid("0fc98a23-fe31-4ef5-8fb9-dd3f479354cd"); - TestData.DeleteInstanceAndData(org, app, 1337, guid); TestData.PrepareInstance(org, app, 1337, guid); // Setup the request @@ -127,7 +124,6 @@ public async Task CreateDataElement_ZeroBytes_BinaryPdf_AnalyserShouldReturnBadR HttpClient client = GetRootedClient(org, app); Guid guid = new Guid("0fc98a23-fe31-4ef5-8fb9-dd3f479354cd"); - TestData.DeleteInstanceAndData(org, app, 1337, guid); TestData.PrepareInstance(org, app, 1337, guid); // Setup the request @@ -163,7 +159,6 @@ public async Task CreateDataElement_JpgFakedAsPdf_AnalyserShouldRunAndFail() HttpClient client = GetRootedClient(org, app); Guid guid = new Guid("1fc98a23-fe31-4ef5-8fb9-dd3f479354ce"); - TestData.DeleteInstanceAndData(org, app, 1337, guid); TestData.PrepareInstance(org, app, 1337, guid); // Setup the request diff --git a/test/Altinn.App.Api.Tests/Controllers/DataController_LayoutEvaluatorTests.cs b/test/Altinn.App.Api.Tests/Controllers/DataController_LayoutEvaluatorTests.cs index ef828f916..54239934e 100644 --- a/test/Altinn.App.Api.Tests/Controllers/DataController_LayoutEvaluatorTests.cs +++ b/test/Altinn.App.Api.Tests/Controllers/DataController_LayoutEvaluatorTests.cs @@ -74,7 +74,6 @@ public async Task PutDataElement_LegacyLayoutEvaluatorState_ReturnsOk() Guid dataGuid = Guid.Parse("f3e04c65-aa70-40ec-84df-087cc2583402"); HttpClient client = GetRootedClient(org, app, 1337, instanceOwnerPartyId); - TestData.DeleteInstanceAndData(org, app, instanceOwnerPartyId, instanceGuid); TestData.PrepareInstance(org, app, instanceOwnerPartyId, instanceGuid); // Update data element diff --git a/test/Altinn.App.Api.Tests/Controllers/DataController_PatchTests.cs b/test/Altinn.App.Api.Tests/Controllers/DataController_PatchTests.cs index 1426e2f78..1b2c6d88a 100644 --- a/test/Altinn.App.Api.Tests/Controllers/DataController_PatchTests.cs +++ b/test/Altinn.App.Api.Tests/Controllers/DataController_PatchTests.cs @@ -66,7 +66,6 @@ public DataControllerPatchTests(WebApplicationFactory factory, ITestOut services.AddSingleton(_dataProcessorMock.Object); services.AddSingleton(_formDataValidatorMock.Object); }; - TestData.DeleteInstanceAndData(Org, App, InstanceOwnerPartyId, _instanceGuid); TestData.PrepareInstance(Org, App, InstanceOwnerPartyId, _instanceGuid); } diff --git a/test/Altinn.App.Api.Tests/Controllers/DataController_PostTests.cs b/test/Altinn.App.Api.Tests/Controllers/DataController_PostTests.cs index 22de25a8d..c0f1abf72 100644 --- a/test/Altinn.App.Api.Tests/Controllers/DataController_PostTests.cs +++ b/test/Altinn.App.Api.Tests/Controllers/DataController_PostTests.cs @@ -33,7 +33,6 @@ public class DataController_PostTests : ApiTestBase, IClassFixture factory, ITestOutputHelper outputHelper) : base(factory, outputHelper) { - TestData.DeleteInstanceAndData(_org, _app, _instanceOwnerPartyId, _instanceGuid); TestData.PrepareInstance(_org, _app, _instanceOwnerPartyId, _instanceGuid); OverrideServicesForAllTests = (services) => { diff --git a/test/Altinn.App.Api.Tests/Controllers/ProcessControllerTests.cs b/test/Altinn.App.Api.Tests/Controllers/ProcessControllerTests.cs index 5a0e5ae51..7c9daba8c 100644 --- a/test/Altinn.App.Api.Tests/Controllers/ProcessControllerTests.cs +++ b/test/Altinn.App.Api.Tests/Controllers/ProcessControllerTests.cs @@ -60,7 +60,6 @@ public ProcessControllerTests(WebApplicationFactory factory, ITestOutpu services.AddSingleton(_dataProcessorMock.Object); services.AddSingleton(_formDataValidatorMock.Object); }; - TestData.DeleteInstanceAndData(Org, App, InstanceOwnerPartyId, _instanceGuid); TestData.PrepareInstance(Org, App, InstanceOwnerPartyId, _instanceGuid); } @@ -74,7 +73,6 @@ public async Task Get_ShouldReturnProcessTasks() HttpClient client = GetRootedClient(org, app, 1337, partyId, 3); - TestData.DeleteInstanceAndData(org, app, partyId, instanceId); TestData.PrepareInstance(org, app, partyId, instanceId); string url = $"/{org}/{app}/instances/{partyId}/{instanceId}/process"; diff --git a/test/Altinn.App.Api.Tests/Controllers/ValidateController_ValidateInstanceTests.cs b/test/Altinn.App.Api.Tests/Controllers/ValidateController_ValidateInstanceTests.cs index ff823ca8c..e6a4d9ae6 100644 --- a/test/Altinn.App.Api.Tests/Controllers/ValidateController_ValidateInstanceTests.cs +++ b/test/Altinn.App.Api.Tests/Controllers/ValidateController_ValidateInstanceTests.cs @@ -51,7 +51,6 @@ ITestOutputHelper outputHelper services.AddSingleton(_dataProcessorMock.Object); services.AddSingleton(_formDataValidatorMock.Object); }; - TestData.DeleteInstanceAndData(Org, App, InstanceOwnerPartyId, InstanceGuid); TestData.PrepareInstance(Org, App, InstanceOwnerPartyId, InstanceGuid); } diff --git a/test/Altinn.App.Api.Tests/CustomWebApplicationFactory.cs b/test/Altinn.App.Api.Tests/CustomWebApplicationFactory.cs index 8d7b35243..2e5733203 100644 --- a/test/Altinn.App.Api.Tests/CustomWebApplicationFactory.cs +++ b/test/Altinn.App.Api.Tests/CustomWebApplicationFactory.cs @@ -215,7 +215,8 @@ private void ConfigureFakeHttpClientHandler(IServiceCollection services) } /// - /// Set this in your test class constructor + /// Helper to quickly verify the status code and deserialize the content of a response. + /// and print the content to output helper /// protected async Task VerifyStatusAndDeserialize( HttpResponseMessage response, @@ -224,7 +225,10 @@ HttpStatusCode expectedStatusCode { // Deserialize content and log everything if it fails var content = await response.Content.ReadAsStringAsync(); - OutputHelper.WriteLine($"Response content: {content}"); + OutputHelper.WriteLine( + $"{response.RequestMessage?.Method} {response.RequestMessage?.RequestUri?.PathAndQuery}" + ); + OutputHelper.WriteLine(JsonUtils.IndentJson(content)); // Verify status code response.Should().HaveStatusCode(expectedStatusCode); try @@ -239,8 +243,6 @@ HttpStatusCode expectedStatusCode OutputHelper.WriteLine( $"Failed to deserialize content of {response.RequestMessage?.Method} request to {response.RequestMessage?.RequestUri} as {ReflectionUtils.GetTypeNameWithGenericArguments()}:" ); - - OutputHelper.WriteLine(JsonUtils.IndentJson(content)); OutputHelper.WriteLine(string.Empty); throw; } diff --git a/test/Altinn.App.Api.Tests/Data/Instances/tdd/.gitignore b/test/Altinn.App.Api.Tests/Data/Instances/.gitignore similarity index 64% rename from test/Altinn.App.Api.Tests/Data/Instances/tdd/.gitignore rename to test/Altinn.App.Api.Tests/Data/Instances/.gitignore index 8c777c01b..fa3349399 100644 --- a/test/Altinn.App.Api.Tests/Data/Instances/tdd/.gitignore +++ b/test/Altinn.App.Api.Tests/Data/Instances/.gitignore @@ -1,4 +1,4 @@ # Ignore guid.json files ????????-????-????-????-????????????.json # ignore copied blobs -*/*/*/blob/????????-????-????-????-???????????? +**/blob/????????-????-????-????-???????????? diff --git a/test/Altinn.App.Api.Tests/Data/Instances/tdd/task-action/1337/b1135209-628e-4a6e-9efd-e4282068ef41.pretest.json b/test/Altinn.App.Api.Tests/Data/Instances/tdd/task-action/1337/b1135209-628e-4a6e-9efd-e4282068ef41.pretest.json index 69ac2d877..cb13d3a91 100644 --- a/test/Altinn.App.Api.Tests/Data/Instances/tdd/task-action/1337/b1135209-628e-4a6e-9efd-e4282068ef41.pretest.json +++ b/test/Altinn.App.Api.Tests/Data/Instances/tdd/task-action/1337/b1135209-628e-4a6e-9efd-e4282068ef41.pretest.json @@ -26,14 +26,5 @@ "isSoftDeleted": false, "isHardDeleted": false, "readStatus": "Read" - }, - "data": [ - { - "id": "de288942-a8af-4f77-a1f1-6e1ede1cd502", - "dataType": "default", - "contentType": "application/xml", - "size": 0, - "locked": false - } - ] + } } diff --git a/test/Altinn.App.Api.Tests/Data/TestData.cs b/test/Altinn.App.Api.Tests/Data/TestData.cs index 88b7d6156..8cdbc3f76 100644 --- a/test/Altinn.App.Api.Tests/Data/TestData.cs +++ b/test/Altinn.App.Api.Tests/Data/TestData.cs @@ -96,6 +96,18 @@ Guid dataGuid return Path.Combine(dataDirectory, $"{dataGuid}.json"); } + public static string GetDataElementBlobContnet( + string org, + string app, + int instanceOwnerId, + Guid instanceGuid, + Guid dataGuid + ) + { + string dataElementPath = GetDataBlobPath(org, app, instanceOwnerId, instanceGuid, dataGuid); + return File.ReadAllText(dataElementPath); + } + public static string GetDataBlobPath(string org, string app, int instanceOwnerId, Guid instanceGuid, Guid dataGuid) { string dataDirectory = GetDataDirectory(org, app, instanceOwnerId, instanceGuid); @@ -142,6 +154,7 @@ public static string GetInstancePath(string org, string app, int instanceOwnerId public static void PrepareInstance(string org, string app, int instanceOwnerId, Guid instanceGuid) { + DeleteInstanceAndData(org, app, instanceOwnerId, instanceGuid); string instancePath = GetInstancePath(org, app, instanceOwnerId, instanceGuid); string preInstancePath = instancePath.Replace(".json", ".pretest.json"); @@ -185,7 +198,7 @@ public static void DeleteInstanceAndData(string org, string app, int instanceOwn } } - public static void DeleteDataForInstance(string org, string app, int instanceOwnerId, Guid instanceGuid) + private static void DeleteDataForInstance(string org, string app, int instanceOwnerId, Guid instanceGuid) { string path = GetDataDirectory(org, app, instanceOwnerId, instanceGuid); diff --git a/test/Altinn.App.Api.Tests/Data/apps/tdd/task-action/config/applicationmetadata.json b/test/Altinn.App.Api.Tests/Data/apps/tdd/task-action/config/applicationmetadata.json index 04fdae29e..f5a79437f 100644 --- a/test/Altinn.App.Api.Tests/Data/apps/tdd/task-action/config/applicationmetadata.json +++ b/test/Altinn.App.Api.Tests/Data/apps/tdd/task-action/config/applicationmetadata.json @@ -1,6 +1,6 @@ { - "id": "ttd/task-action", - "org": "ttd", + "id": "tdd/task-action", + "org": "tdd", "title": { "nb": "task-action" }, @@ -25,7 +25,7 @@ ], "appLogic": { "autoCreate": true, - "classRef": "Altinn.App.Models.Scheme", + "classRef": "Altinn.App.Api.Tests.Data.apps.tdd.task_action.config.models.Scheme", "allowAnonymousOnStateless": false, "autoDeleteOnProcessEnd": false }, @@ -50,4 +50,4 @@ "createdBy": "tjololo", "lastChanged": "2023-05-31T08:03:25.9385925Z", "lastChangedBy": "tjololo" -} \ No newline at end of file +} diff --git a/test/Altinn.App.Api.Tests/Data/apps/tdd/task-action/config/models/Scheme.cs b/test/Altinn.App.Api.Tests/Data/apps/tdd/task-action/config/models/Scheme.cs new file mode 100644 index 000000000..84adfbabd --- /dev/null +++ b/test/Altinn.App.Api.Tests/Data/apps/tdd/task-action/config/models/Scheme.cs @@ -0,0 +1,18 @@ +#pragma warning disable IDE1006 // Naming Styles +namespace Altinn.App.Api.Tests.Data.apps.tdd.task_action.config.models; + +/// +/// Class for the model +/// +public class Scheme +{ + public string? name { get; set; } + + public string? description { get; set; } + + public string? TestCustomButtonInput { get; set; } + + public string? TestCustomButtonReadOnlyInput { get; set; } +} + +#pragma warning restore IDE1006 // Naming Styles