This is an automated email from the ASF dual-hosted git repository. danhaywood pushed a commit to branch CAUSEWAY-3718 in repository https://gitbox.apache.org/repos/asf/causeway.git
commit fe1404fa2b7d24a8c50ebec73b85e62ca0a9abb3 Author: danhaywood <[email protected]> AuthorDate: Fri Apr 5 09:53:03 2024 +0100 CAUSEWAY-3718: adds failing integ test to demonstrate the issue --- viewers/restfulobjects/test/pom.xml | 6 + .../restfulobjects/test/domain/dom/Staff.java | 12 ++ .../test/scenarios/staff/Staff_IntegTest.java | 163 +++++++++++++++++++++ 3 files changed, 181 insertions(+) diff --git a/viewers/restfulobjects/test/pom.xml b/viewers/restfulobjects/test/pom.xml index bd9d4d2400..9ba9f05a37 100644 --- a/viewers/restfulobjects/test/pom.xml +++ b/viewers/restfulobjects/test/pom.xml @@ -173,5 +173,11 @@ <scope>test</scope> </dependency> + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <scope>test</scope> + </dependency> + </dependencies> </project> diff --git a/viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/domain/dom/Staff.java b/viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/domain/dom/Staff.java index 11923234d1..23e83f6a6d 100644 --- a/viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/domain/dom/Staff.java +++ b/viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/domain/dom/Staff.java @@ -27,6 +27,7 @@ import org.apache.causeway.applib.annotation.Action; import org.apache.causeway.applib.annotation.DomainService; import org.apache.causeway.applib.annotation.PriorityPrecedence; import org.apache.causeway.applib.annotation.SemanticsOf; +import org.apache.causeway.applib.value.Blob; import lombok.RequiredArgsConstructor; @@ -46,6 +47,17 @@ public class Staff { return staffMemberRepository.create(name, department); } + @Action(semantics = SemanticsOf.NON_IDEMPOTENT) + public StaffMember createStaffMemberWithPhoto( + final String name, + final Department department, + final Blob photo + ){ + final var staffMember = createStaffMember(name, department); + staffMember.setPhoto(photo); + return staffMember; + } + @Action(semantics = SemanticsOf.SAFE) public List<StaffMember> findAllStaffMembers(){ return staffMemberRepository.findAll(); diff --git a/viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_IntegTest.java b/viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_IntegTest.java new file mode 100644 index 0000000000..2c3dcc72c3 --- /dev/null +++ b/viewers/restfulobjects/test/src/test/java/org/apache/causeway/viewer/restfulobjects/test/scenarios/staff/Staff_IntegTest.java @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.causeway.viewer.restfulobjects.test.scenarios.staff; + +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.Invocation; +import javax.ws.rs.core.Response; + +import org.apache.causeway.applib.services.bookmark.Bookmark; +import org.apache.causeway.core.metamodel.facets.param.choices.ActionParameterChoicesFacetFromAction; + +import org.apache.causeway.viewer.restfulobjects.test.domain.dom.Department; + +import org.approvaltests.Approvals; +import org.approvaltests.reporters.DiffReporter; +import org.approvaltests.reporters.UseReporter; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.causeway.viewer.restfulobjects.test.scenarios.Abstract_IntegTest; + +import org.springframework.http.HttpStatus; +import org.springframework.http.converter.json.GsonBuilderUtils; +import org.springframework.transaction.annotation.Propagation; + +import lombok.Getter; +import lombok.SneakyThrows; +import lombok.val; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.Base64; +import java.util.Optional; + +import com.google.common.io.Resources; +import com.google.gson.GsonBuilder; + +public class Staff_IntegTest extends Abstract_IntegTest { + + private GsonBuilder gsonBuilder; + + @BeforeEach + void setup() { + gsonBuilder = new GsonBuilder(); + } + + @SneakyThrows + @Test + @UseReporter(DiffReporter.class) + public void can_create_staff_member() { + + // given + final var staffName = "Fred Smith"; + + final var bookmarkBeforeIfAny = transactionService.callTransactional(Propagation.REQUIRED, () -> { + final var staffMember = staffMemberRepository.findByName(staffName); + return bookmarkService.bookmarkFor(staffMember); + }).valueAsNonNullElseFail(); + + assertThat(bookmarkBeforeIfAny).isEmpty(); + + final var photoEncoded = readFileAndEncodeAsBlob("StaffMember-photo-Bar.pdf"); + final var requestBuilder = restfulClient.request("services/university.dept.Staff/actions/createStaffMemberWithPhoto/invoke"); + + final var body = new Body(staffName, "Classics", photoEncoded); + final var bodyJson = gsonBuilder.create().toJson(body); + + // when + val response = requestBuilder.post(Entity.entity(bodyJson, "application/json")); + + // then + assertThat(response.getStatusInfo().getFamily()).isEqualTo(Response.Status.Family.SUCCESSFUL); + assertThat(response.getStatus()).isEqualTo(Response.Status.OK.getStatusCode()); + + // and also json response + val entity = response.readEntity(String.class); + assertThat(response) + .extracting(Response::getStatus) + .isEqualTo(Response.Status.OK.getStatusCode()); + Approvals.verify(entity, jsonOptions()); + + // and also object is created in database + final var bookmarkAfterIfAny = transactionService.callTransactional(Propagation.REQUIRED, () -> { + final var staffMember = staffMemberRepository.findByName(staffName); + return bookmarkService.bookmarkFor(staffMember); + }).valueAsNonNullElseFail(); + assertThat(bookmarkAfterIfAny).isNotEmpty(); + } + + private String readFileAndEncodeAsBlob(String fileName) throws IOException, URISyntaxException { + byte[] bytes = Resources.toByteArray(Resources.getResource(Abstract_IntegTest.class, fileName)); + String photoEncoded = encodePdf(fileName, bytes); + return photoEncoded; + } + + private String encodePdf(final String fileName, final byte[] pdfBytes) throws URISyntaxException { + final String pdfBytesEncoded = Base64.getEncoder().encodeToString(pdfBytes); + final String encodedBlob = String.format("%s:%s:%s", fileName, "application/pdf", pdfBytesEncoded); + return encodedBlob; + } + +} + + +@Getter +class Body { + + /** + * @param nameValue + * @param departmentValue + * @param blobValue - is the Blob encoded format: "filename.pdf:application/pdf:pdfBytesBase64Encoded" + */ + Body(String nameValue, String departmentValue, String blobValue) { + photo = new Blob(); + photo.value = blobValue; + name = new Name(); + name.value = nameValue; + department = new Department(); + department.value = departmentValue; + } + + private Name name; + + private Department department; + + private Blob photo; + + @Getter + static class Name { + private String value; + } + + @Getter + static class Department { + private String value; + } + + @Getter + static class Blob { + private String value; + } + +} +
