From 7ebb4f0d384b1820f5d98f43cf7180988d58a589 Mon Sep 17 00:00:00 2001 From: Lars Johansson <lars.johansson@ess.eu> Date: Fri, 12 Jan 2024 15:20:04 +0100 Subject: [PATCH] Add integration tests for conversion of names and structures data from one format to another --- README.md | 2 +- docker-compose-demo.yml | 2 +- .../openepics/names/rest/api/v1/IConvert.java | 2 +- .../org/openepics/names/docker/ConvertIT.java | 270 ++++++++++++++++++ .../org/openepics/names/docker/ITUtil.java | 85 +++++- .../openepics/names/docker/ITUtilNames.java | 81 ++++++ .../names/docker/ITUtilStructures.java | 80 ++++++ .../resources/INTEGRATIONTEST_DOCKER_RUN.md | 1 + .../resources/{db/data => data/db}/README.txt | 2 +- .../db}/dump-discs_names_namesit.sql | 0 .../db}/dump-discs_names_subsystemit.sql | 0 .../NameElementCommand_create_name.xlsx | Bin 0 -> 7279 bytes .../NameElementCommand_create_names.xlsx | Bin 0 -> 7407 bytes ...tructureElementCommand_create_system.xlsx} | Bin ...tructureElementCommand_create_systems.xlsx | Bin 0 -> 7499 bytes .../NameElementCommand_name_create.xlsx | Bin 7409 -> 0 bytes 16 files changed, 511 insertions(+), 14 deletions(-) create mode 100644 src/test/java/org/openepics/names/docker/ConvertIT.java rename src/test/resources/{db/data => data/db}/README.txt (94%) rename src/test/resources/{db/data => data/db}/dump-discs_names_namesit.sql (100%) rename src/test/resources/{db/data => data/db}/dump-discs_names_subsystemit.sql (100%) create mode 100644 src/test/resources/data/templates/NameElementCommand_create_name.xlsx create mode 100644 src/test/resources/data/templates/NameElementCommand_create_names.xlsx rename src/test/resources/{db/data/templates/StructureElementCommand_system_create.xlsx => data/templates/StructureElementCommand_create_system.xlsx} (100%) create mode 100644 src/test/resources/data/templates/StructureElementCommand_create_systems.xlsx delete mode 100644 src/test/resources/db/data/templates/NameElementCommand_name_create.xlsx diff --git a/README.md b/README.md index 7aa8fe5e..52f57c3a 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ See ``` postgres: volumes: - - ./src/test/resources/db/data/dump-discs_names_namesit.sql:/docker-entrypoint-initdb.d/dump-discs_names_namesit.sql + - ./src/test/resources/data/db/dump-discs_names_namesit.sql:/docker-entrypoint-initdb.d/dump-discs_names_namesit.sql ``` * Test diff --git a/docker-compose-demo.yml b/docker-compose-demo.yml index a11410ae..8a1a1f73 100644 --- a/docker-compose-demo.yml +++ b/docker-compose-demo.yml @@ -34,7 +34,7 @@ services: timeout: 5s retries: 10 volumes: - - ./src/test/resources/db/data/dump-discs_names_namesit.sql:/docker-entrypoint-initdb.d/dump-discs_names_namesit.sql + - ./src/test/resources/data/db/dump-discs_names_namesit.sql:/docker-entrypoint-initdb.d/dump-discs_names_namesit.sql volumes: naming-data: diff --git a/src/main/java/org/openepics/names/rest/api/v1/IConvert.java b/src/main/java/org/openepics/names/rest/api/v1/IConvert.java index f9ce6ef6..7dc8c9e0 100644 --- a/src/main/java/org/openepics/names/rest/api/v1/IConvert.java +++ b/src/main/java/org/openepics/names/rest/api/v1/IConvert.java @@ -49,7 +49,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; * @author Lars Johansson */ @Tag(name = "4. Convert", - description = "handle conversion of names and structure data from one format to another for Naming application") + description = "handle conversion of names and structures data from one format to another for Naming application") @RequestMapping("/api/v1/convert") public interface IConvert { diff --git a/src/test/java/org/openepics/names/docker/ConvertIT.java b/src/test/java/org/openepics/names/docker/ConvertIT.java new file mode 100644 index 00000000..fcbbaf7f --- /dev/null +++ b/src/test/java/org/openepics/names/docker/ConvertIT.java @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2024 European Spallation Source ERIC. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +package org.openepics.names.docker; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.File; +import java.util.UUID; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.openepics.names.rest.beans.Type; +import org.openepics.names.rest.beans.element.NameElement; +import org.openepics.names.rest.beans.element.NameElementCommandCreate; +import org.openepics.names.rest.beans.element.StructureElement; +import org.openepics.names.rest.beans.element.StructureElementCommandCreate; +import org.openepics.names.rest.beans.response.ResponsePageNameElements; +import org.openepics.names.rest.beans.response.ResponsePageStructureElements; +import org.testcontainers.containers.ComposeContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +/** + * Integration tests for Naming and PostgreSQL that make use of existing dockerization + * with docker-compose-integrationtest.yml / Dockerfile.integrationtest. + * + * <p> + * Purpose of this class is to test conversion of names and structures data from one format to another. + * </p> + * + * @author Lars Johansson + * @see NamesIT + * @see NamesIT#readSearchHistoryDeleted() + */ +@Testcontainers +class ConvertIT { + + @Container + public static final ComposeContainer ENVIRONMENT = ITUtil.defaultComposeContainers(); + + private static UUID systemGroupAcc = null; + private static UUID systemRFQ = null; + private static UUID subsystem010 = null; + + private static UUID disciplineEMR = null; + private static UUID deviceGroupEMR = null; + private static UUID deviceTypeFS = null; + + @BeforeAll + public static void initAll() { + // init system group, system, subsystem, discipline, device group, device type + + StructureElementCommandCreate structureElementCommandCreate = null; + StructureElement approvedStructureElement = null; + NameElementCommandCreate nameElementCommandCreate = null; +// NameElement nameElement = null; + + structureElementCommandCreate = new StructureElementCommandCreate( + Type.SYSTEMGROUP, null, + "Accelerator", "Acc", + "The ESS Linear Accelerator", "approved by alfio"); + approvedStructureElement = ITUtilStructures.assertCreateApprove(structureElementCommandCreate); + systemGroupAcc = approvedStructureElement.getUuid(); + + structureElementCommandCreate = new StructureElementCommandCreate( + Type.SYSTEM, systemGroupAcc, + "Radio Frequency Quadrupole", "RFQ", + "empty", "empty"); + approvedStructureElement = ITUtilStructures.assertCreateApprove(structureElementCommandCreate); + systemRFQ = approvedStructureElement.getUuid(); + + structureElementCommandCreate = new StructureElementCommandCreate( + Type.SUBSYSTEM, systemRFQ, + "01 Phase Reference Line", "010PRL", + "empty", "Approved by Daniel Piso"); + approvedStructureElement = ITUtilStructures.assertCreateApprove(structureElementCommandCreate); + + structureElementCommandCreate = new StructureElementCommandCreate( + Type.SUBSYSTEM, systemRFQ, + "RFQ-010", "010", + "empty", "Approved by Daniel Piso"); + approvedStructureElement = ITUtilStructures.assertCreateApprove(structureElementCommandCreate); + subsystem010 = approvedStructureElement.getUuid(); + + structureElementCommandCreate = new StructureElementCommandCreate( + Type.SUBSYSTEM, systemRFQ, + "Power switch board 01", "N1U1", + "Electrical power cabinets", "Approved by Daniel Piso"); + approvedStructureElement = ITUtilStructures.assertCreateApprove(structureElementCommandCreate); + + structureElementCommandCreate = new StructureElementCommandCreate( + Type.DISCIPLINE, null, + "Electromagnetic Resonators", "EMR", + "empty", "empty"); + approvedStructureElement = ITUtilStructures.assertCreateApprove(structureElementCommandCreate); + disciplineEMR = approvedStructureElement.getUuid(); + + structureElementCommandCreate = new StructureElementCommandCreate( + Type.DEVICEGROUP, disciplineEMR, + "Control", null, + "empty", "These names are needed now, so I am approving, but please add a description to these later."); + approvedStructureElement = ITUtilStructures.assertCreateApprove(structureElementCommandCreate); + deviceGroupEMR = approvedStructureElement.getUuid(); + + structureElementCommandCreate = new StructureElementCommandCreate( + Type.DEVICETYPE, deviceGroupEMR, + "Flow Switch", "FS", + "empty", "Approve names added from misc device group"); + approvedStructureElement = ITUtilStructures.assertCreateApprove(structureElementCommandCreate); + deviceTypeFS = approvedStructureElement.getUuid(); + + structureElementCommandCreate = new StructureElementCommandCreate( + Type.DEVICETYPE, deviceGroupEMR, + "RF Antenna", "RFA", + "empty", "Approve names added from misc device group"); + approvedStructureElement = ITUtilStructures.assertCreateApprove(structureElementCommandCreate); + + structureElementCommandCreate = new StructureElementCommandCreate( + Type.DEVICETYPE, deviceGroupEMR, + "Temperature Transmitter", "TT", + "empty", "Approve names added from misc device group"); + approvedStructureElement = ITUtilStructures.assertCreateApprove(structureElementCommandCreate); + + nameElementCommandCreate = new NameElementCommandCreate( + subsystem010, deviceTypeFS, "001", + "description", "comment"); + ITUtilNames.assertCreate(nameElementCommandCreate); + + nameElementCommandCreate = new NameElementCommandCreate( + subsystem010, deviceTypeFS, "002", + "description", "comment"); + ITUtilNames.assertCreate(nameElementCommandCreate); + + nameElementCommandCreate = new NameElementCommandCreate( + subsystem010, deviceTypeFS, "003", + "description", "comment"); + ITUtilNames.assertCreate(nameElementCommandCreate); + } + + @AfterAll + public static void extractJacocoReport() { + // extract jacoco report from container file system + ITUtil.extractJacocoReport(ENVIRONMENT, + ITUtil.JACOCO_TARGET_PREFIX + ConvertIT.class.getSimpleName() + ITUtil.JACOCO_TARGET_SUFFIX); + } + + @Test + void json2ExcelStructure() { + // purpose + // test convert structures data in json, according to array of structure elements, to Excel file + // + // note + // response - no content (null) if response is not json + + ResponsePageStructureElements responsePage = ITUtilStructures.assertRead("/children/" + systemGroupAcc.toString(), 1); + String response = ITUtilStructures.assertConvertJson2Excel(responsePage.getList().stream().toArray(StructureElement[]::new)); + + assertNotNull(responsePage); + assertNull(response); + } + + @Test + void json2ExcelStructures() { + // purpose + // test convert structures data in json, according to array of structure elements, to Excel file + // + // note + // response - no content (null) if response is not json + + ResponsePageStructureElements responsePage = ITUtilStructures.assertRead("/children/" + systemRFQ.toString(), 3); + String response = ITUtilStructures.assertConvertJson2Excel(responsePage.getList().stream().toArray(StructureElement[]::new)); + + assertNotNull(responsePage); + assertNull(response); + } + + @Test + void json2ExcelName() { + // purpose + // test convert names data in json, according to array of structure elements, to Excel file + // + // note + // response - no content (null) if response is not json + + ResponsePageNameElements responsePage = ITUtilNames.assertRead("?index=001", 1); + String response = ITUtilNames.assertConvertJson2Excel(responsePage.getList().stream().toArray(NameElement[]::new)); + + assertNotNull(responsePage); + assertNull(response); + } + + @Test + void json2ExcelNames() { + // purpose + // test convert names data in json, according to array of structure elements, to Excel file + // + // note + // response - no content (null) if response is not json + + ResponsePageNameElements responsePage = ITUtilNames.assertRead("?index=00%", 3); + String response = ITUtilNames.assertConvertJson2Excel(responsePage.getList().stream().toArray(NameElement[]::new)); + + assertNotNull(responsePage); + assertNull(response); + } + + @Test + void excel2JsonStructure() { + // purpose + // test convert structures data in Excel file, according to template for structures, to json + + String json = ITUtilStructures.assertConvertExcel2Json(new File("src/test/resources/data/templates/StructureElementCommand_create_system.xlsx")); + + assertNotNull(json); + assertTrue(json.length() > 0); + } + + @Test + void excel2JsonStructures() { + // purpose + // test convert structures data in Excel file, according to template for structures, to json + + String json = ITUtilStructures.assertConvertExcel2Json(new File("src/test/resources/data/templates/StructureElementCommand_create_systems.xlsx")); + + assertNotNull(json); + assertTrue(json.length() > 0); + } + + @Test + void excel2JsonName() { + // purpose + // test convert names data in Excel file, according to template for structures, to json + + String json = ITUtilNames.assertConvertExcel2Json(new File("src/test/resources/data/templates/NameElementCommand_create_name.xlsx")); + + assertNotNull(json); + assertTrue(json.length() > 0); + } + + @Test + void excel2JsonNames() { + // purpose + // test convert names data in Excel file, according to template for structures, to json + + String json = ITUtilNames.assertConvertExcel2Json(new File("src/test/resources/data/templates/NameElementCommand_create_names.xlsx")); + + assertNotNull(json); + assertTrue(json.length() > 0); + } + +} diff --git a/src/test/java/org/openepics/names/docker/ITUtil.java b/src/test/java/org/openepics/names/docker/ITUtil.java index a5a39539..a2e35219 100644 --- a/src/test/java/org/openepics/names/docker/ITUtil.java +++ b/src/test/java/org/openepics/names/docker/ITUtil.java @@ -59,10 +59,15 @@ public class ITUtil { static final String AUTH_ADMIN = "admin:adminPass"; static final String EMPTY_JSON = "[]"; static final String HTTP = "http://"; - static final String HEADER_JSON = "'Content-Type: application/json'"; + + static final String HEADER_ACCEPT_APPLICATION_JSON = "'accept: application/json'"; + static final String HEADER_ACCEPT_APPLICATION_VND_MS_EXCEL = "'accept: application/vnd.ms-excel'"; + static final String HEADER_CONTENT_TYPE_APPLICATION_JSON = "'Content-Type: application/json'"; + static final String HEADER_CONTENT_TYPE_MULTIPART_FORM_DATA = "'Content-Type: multipart/form-data'"; static final String IP_PORT_NAMING = "127.0.0.1:8080"; + static final String API_V1_CONVERT = "/api/v1/convert"; static final String API_V1_HISTORY = "/api/v1/history"; static final String API_V1_NAMES = "/api/v1/names"; static final String API_V1_STRUCTURES = "/api/v1/structures"; @@ -418,7 +423,42 @@ public class ITUtil { static enum AuthorizationChoice {NONE, USER, ADMIN}; // enum for different endpoints - static enum EndpointChoice {NAMES, STRUCTURES}; + static enum EndpointChoice {NAMES, STRUCTURES, CONVERT}; + + /** + * Utility method to return curl for POST with path and json. + * + * @param authorizationChoice authorization choice + * @param endpointChoice endpoint choice + * @param path particular path + * @param json json data + * @return curl for POST with path and json + */ + static String curlPostPathJson2Excel(AuthorizationChoice authorizationChoice, EndpointChoice endpointChoice, String path, String json) { + StringBuilder header = new StringBuilder(); + header.append(" -H " + HEADER_ACCEPT_APPLICATION_VND_MS_EXCEL); + header.append(" -H " + HEADER_CONTENT_TYPE_APPLICATION_JSON); + + return curlMethodAuthEndpointPathJson(header.toString(), MethodChoice.POST, authorizationChoice, endpointChoice, path, json); + } + + /** + * Utility method to return curl for POST with path. + * + * @param authorizationChoice authorization choice + * @param endpointChoice endpoint choice + * @param path particular path + * @param file file + * @return curl for POST with path + */ + static String curlPostPathExcel2Json(AuthorizationChoice authorizationChoice, EndpointChoice endpointChoice, String path, File file) { + StringBuilder header = new StringBuilder(); + header.append(" -H " + HEADER_ACCEPT_APPLICATION_JSON); + header.append(" -H " + HEADER_CONTENT_TYPE_MULTIPART_FORM_DATA); + header.append(" -F 'file=@" + file.getPath() + ";type=application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'"); + + return curlMethodAuthEndpointPathJson(header.toString(), MethodChoice.POST, authorizationChoice, endpointChoice, path, null); + } /** * Utility method to return curl for POST (create information) with path and json. @@ -427,7 +467,7 @@ public class ITUtil { * @param endpointChoice endpoint choice * @param path particular path * @param json json data - * @return curl for POST property (create information) with path and json + * @return curl for POST (create information) with path and json */ static String curlPostPathJson(AuthorizationChoice authorizationChoice, EndpointChoice endpointChoice, String path, String json) { return curlMethodAuthEndpointPathJson(MethodChoice.POST, authorizationChoice, endpointChoice, path, json); @@ -440,7 +480,7 @@ public class ITUtil { * @param endpointChoice endpoint choice * @param path particular path * @param json json data - * @return curl for GET property (get information) with path and json + * @return curl for GET (get information) with path and json */ static String curlGetPathJson(AuthorizationChoice authorizationChoice, EndpointChoice endpointChoice, String path, String json) { return curlMethodAuthEndpointPathJson(MethodChoice.GET, authorizationChoice, endpointChoice, path, json); @@ -453,7 +493,7 @@ public class ITUtil { * @param endpointChoice endpoint choice * @param path particular path * @param json json data - * @return curl for PUT property (update information) with path and json + * @return curl for PUT (update information) with path and json */ static String curlPutPathJson(AuthorizationChoice authorizationChoice, EndpointChoice endpointChoice, String path, String json) { return curlMethodAuthEndpointPathJson(MethodChoice.PUT, authorizationChoice, endpointChoice, path, json); @@ -466,7 +506,7 @@ public class ITUtil { * @param endpointChoice endpoint choice * @param path particular path * @param json json data - * @return curl for DELETE property (delete information) with path + * @return curl for DELETE (delete information) with path and json */ static String curlDeletePathJson(AuthorizationChoice authorizationChoice, EndpointChoice endpointChoice, String path, String json) { return curlMethodAuthEndpointPathJson(MethodChoice.DELETE, authorizationChoice, endpointChoice, path, json); @@ -479,7 +519,7 @@ public class ITUtil { * @param endpointChoice endpoint choice * @param path particular path * @param json json data - * @return + * @return curl for PATCH with path and json */ static String curlPatchPathJson(AuthorizationChoice authorizationChoice, EndpointChoice endpointChoice, String path, String json) { return curlMethodAuthEndpointPathJson(MethodChoice.PATCH, authorizationChoice, endpointChoice, path, json); @@ -496,6 +536,20 @@ public class ITUtil { * @return curl command to run */ private static String curlMethodAuthEndpointPathJson(MethodChoice methodChoice, AuthorizationChoice authorizationChoice, EndpointChoice endpointChoice, String path, String json) { + return curlMethodAuthEndpointPathJson(null, methodChoice, authorizationChoice, endpointChoice, path, json); + } + /** + * Prepare curl command for test to run for contacting server. + * + * @param header header + * @param methodChoice method choice + * @param authorizationChoice authorization choice + * @param endpointChoice endpoint choice + * @param path particular path + * @param json json data + * @return curl command to run + */ + private static String curlMethodAuthEndpointPathJson(String header, MethodChoice methodChoice, AuthorizationChoice authorizationChoice, EndpointChoice endpointChoice, String path, String json) { String pathstr = !StringUtils.isEmpty(path) ? path : ""; @@ -504,10 +558,19 @@ public class ITUtil { ? " -d '" + json + "'" : ""; + String optionHeader = !StringUtils.isEmpty(header) + ? header + : !StringUtils.isEmpty(json) + ? " -H " + ITUtil.HEADER_CONTENT_TYPE_APPLICATION_JSON + : ""; + + String options = + optionHeader + + " -X" + ITUtil.getMethodString(methodChoice) + + " -i "; + return "curl" - + " -H " + ITUtil.HEADER_JSON - + " -X" + ITUtil.getMethodString(methodChoice) - + " -i " + + options + ITUtil.HTTP + ITUtil.getAuthorizationString(authorizationChoice) + ITUtil.IP_PORT_NAMING @@ -570,6 +633,8 @@ public class ITUtil { return ITUtil.API_V1_NAMES; case STRUCTURES: return ITUtil.API_V1_STRUCTURES; + case CONVERT: + return ITUtil.API_V1_CONVERT; default: return StringUtils.EMPTY; } diff --git a/src/test/java/org/openepics/names/docker/ITUtilNames.java b/src/test/java/org/openepics/names/docker/ITUtilNames.java index bbaa1546..1df17ede 100644 --- a/src/test/java/org/openepics/names/docker/ITUtilNames.java +++ b/src/test/java/org/openepics/names/docker/ITUtilNames.java @@ -25,6 +25,7 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import java.io.File; import java.io.IOException; import java.net.HttpURLConnection; import java.util.Map; @@ -67,6 +68,21 @@ public class ITUtilNames { // ---------------------------------------------------------------------------------------------------- + /** + * Return string for name element array. + * + * @param value name element array + * @return string for name element array + */ + static String object2Json(NameElement[] value) { + try { + return mapper.writeValueAsString(value); + } catch (JsonProcessingException e) { + fail(); + } + return null; + } + /** * Return string for name element command array. * @@ -81,6 +97,7 @@ public class ITUtilNames { } return null; } + /** * Return string for name element command array. * @@ -95,6 +112,7 @@ public class ITUtilNames { } return null; } + /** * Return string for name element command array. * @@ -240,6 +258,69 @@ public class ITUtilNames { // ---------------------------------------------------------------------------------------------------- + /** + * @see ITUtilNames#assertConvertExcel2Json(File, int) + */ + public static String assertConvertExcel2Json(File file) { + return assertConvertExcel2Json(file, HttpURLConnection.HTTP_OK); + } + /** + * Utility method to convert Excel to json and assert response code. + * + * @param file file + * @param expectedResponseCode expected response code + * @return json + */ + public static String assertConvertExcel2Json(File file, int expectedResponseCode) { + try { + String[] response = null; + + response = ITUtil.runShellCommand(ITUtil.curlPostPathExcel2Json(AuthorizationChoice.NONE, EndpointChoice.CONVERT, "/excel2Json/names", file)); + ITUtil.assertResponseLength2Code(response, expectedResponseCode); + + return response[1]; + } catch (IOException e) { + fail(); + } catch (Exception e) { + fail(); + } + return null; + } + + // ---------------------------------------------------------------------------------------------------- + + /** + * @see ITUtilNames#assertConvertJson2Excel(NameElement[], int) + */ + public static String assertConvertJson2Excel(NameElement[] nameElements) { + return assertConvertJson2Excel(nameElements, HttpURLConnection.HTTP_OK); + } + /** + * Utility method to convert json to Excel and assert response code. + * + * @param nameElements name elements + * @param expectedResponseCode expected response code + * @return response for Excel file + */ + public static String assertConvertJson2Excel(NameElement[] nameElements, int expectedResponseCode) { + try { + // response - no content (null) if response is not json + String[] response = null; + + response = ITUtil.runShellCommand(ITUtil.curlPostPathJson2Excel(AuthorizationChoice.NONE, EndpointChoice.CONVERT, "/json2Excel/names", object2Json(nameElements))); + ITUtil.assertResponseLength2Code(response, expectedResponseCode); + + return response[1]; + } catch (IOException e) { + fail(); + } catch (Exception e) { + fail(); + } + return null; + } + + // ---------------------------------------------------------------------------------------------------- + /** * @see ITUtilNames#assertFind(String, int) */ diff --git a/src/test/java/org/openepics/names/docker/ITUtilStructures.java b/src/test/java/org/openepics/names/docker/ITUtilStructures.java index b20a63bb..b5606bb9 100644 --- a/src/test/java/org/openepics/names/docker/ITUtilStructures.java +++ b/src/test/java/org/openepics/names/docker/ITUtilStructures.java @@ -25,6 +25,7 @@ import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import java.io.File; import java.io.IOException; import java.net.HttpURLConnection; import java.util.Map; @@ -68,6 +69,21 @@ public class ITUtilStructures { // ---------------------------------------------------------------------------------------------------- + /** + * Return string for structure element array. + * + * @param value structure element array + * @return string for structure element array + */ + static String object2Json(StructureElement[] value) { + try { + return mapper.writeValueAsString(value); + } catch (JsonProcessingException e) { + fail(); + } + return null; + } + /** * Return string for structure element command array. * @@ -243,6 +259,70 @@ public class ITUtilStructures { // ---------------------------------------------------------------------------------------------------- + + /** + * @see ITUtilStructures#assertConvertExcel2Json(File, int) + */ + public static String assertConvertExcel2Json(File file) { + return assertConvertExcel2Json(file, HttpURLConnection.HTTP_OK); + } + /** + * Utility method to convert Excel to json and assert response code. + * + * @param file file + * @param expectedResponseCode expected response code + * @return json + */ + public static String assertConvertExcel2Json(File file, int expectedResponseCode) { + try { + String[] response = null; + + response = ITUtil.runShellCommand(ITUtil.curlPostPathExcel2Json(AuthorizationChoice.NONE, EndpointChoice.CONVERT, "/excel2Json/structures", file)); + ITUtil.assertResponseLength2Code(response, expectedResponseCode); + + return response[1]; + } catch (IOException e) { + fail(); + } catch (Exception e) { + fail(); + } + return null; + } + + // ---------------------------------------------------------------------------------------------------- + + /** + * @see ITUtilStructures#assertConvertJson2Excel(StructureElement[], int) + */ + public static String assertConvertJson2Excel(StructureElement[] structureElements) { + return assertConvertJson2Excel(structureElements, HttpURLConnection.HTTP_OK); + } + /** + * Utility method to convert json to Excel and assert response code. + * + * @param structureElements structure elements + * @param expectedResponseCode expected response code + * @return response for Excel file + */ + public static String assertConvertJson2Excel(StructureElement[] structureElements, int expectedResponseCode) { + try { + // response - no content (null) if response is not json + String[] response = null; + + response = ITUtil.runShellCommand(ITUtil.curlPostPathJson2Excel(AuthorizationChoice.NONE, EndpointChoice.CONVERT, "/json2Excel/structures", object2Json(structureElements))); + ITUtil.assertResponseLength2Code(response, expectedResponseCode); + + return response[1]; + } catch (IOException e) { + fail(); + } catch (Exception e) { + fail(); + } + return null; + } + + // ---------------------------------------------------------------------------------------------------- + /** * @see ITUtilStructures#assertFind(String, int) */ diff --git a/src/test/resources/INTEGRATIONTEST_DOCKER_RUN.md b/src/test/resources/INTEGRATIONTEST_DOCKER_RUN.md index 60c6df18..f983761c 100644 --- a/src/test/resources/INTEGRATIONTEST_DOCKER_RUN.md +++ b/src/test/resources/INTEGRATIONTEST_DOCKER_RUN.md @@ -28,6 +28,7 @@ mvn failsafe:integration-test -DskipITs=false -DskipITCoverage=false To run individual integration tests (classes) via Maven. ``` +mvn test -Dtest=org.openepics.names.docker.ConvertIT mvn test -Dtest=org.openepics.names.docker.HealthcheckIT mvn test -Dtest=org.openepics.names.docker.NamesIT mvn test -Dtest=org.openepics.names.docker.ReportIT diff --git a/src/test/resources/db/data/README.txt b/src/test/resources/data/db/README.txt similarity index 94% rename from src/test/resources/db/data/README.txt rename to src/test/resources/data/db/README.txt index 5f132e02..0f1359dd 100644 --- a/src/test/resources/db/data/README.txt +++ b/src/test/resources/data/db/README.txt @@ -18,7 +18,7 @@ Backup done with DBeaver tool Restore to be done with psql make sure database container is up and running e.g. - psql --host=localhost --port=5432 --dbname=discs_names --username=discs_names < ......../naming-backend/src/test/resources/db/data/dump-discs_names_subsystemit.sql + psql --host=localhost --port=5432 --dbname=discs_names --username=discs_names < ......../naming-backend/src/test/resources/data/db/dump-discs_names_subsystemit.sql DBeaver https://dbeaver.io/ diff --git a/src/test/resources/db/data/dump-discs_names_namesit.sql b/src/test/resources/data/db/dump-discs_names_namesit.sql similarity index 100% rename from src/test/resources/db/data/dump-discs_names_namesit.sql rename to src/test/resources/data/db/dump-discs_names_namesit.sql diff --git a/src/test/resources/db/data/dump-discs_names_subsystemit.sql b/src/test/resources/data/db/dump-discs_names_subsystemit.sql similarity index 100% rename from src/test/resources/db/data/dump-discs_names_subsystemit.sql rename to src/test/resources/data/db/dump-discs_names_subsystemit.sql diff --git a/src/test/resources/data/templates/NameElementCommand_create_name.xlsx b/src/test/resources/data/templates/NameElementCommand_create_name.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..daffac29e46d1ce4f9226a9104f68dc2f3919458 GIT binary patch literal 7279 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 literal 0 HcmV?d00001 diff --git a/src/test/resources/data/templates/NameElementCommand_create_names.xlsx b/src/test/resources/data/templates/NameElementCommand_create_names.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f6e39e10fb9b9ba01ef93d122d5c5181dee99dce GIT binary patch literal 7407 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 Xr>2MuO+Pp|Z0JW1n!|o%u&4h4d$(A@ literal 0 HcmV?d00001 diff --git a/src/test/resources/db/data/templates/StructureElementCommand_system_create.xlsx b/src/test/resources/data/templates/StructureElementCommand_create_system.xlsx similarity index 100% rename from src/test/resources/db/data/templates/StructureElementCommand_system_create.xlsx rename to src/test/resources/data/templates/StructureElementCommand_create_system.xlsx diff --git a/src/test/resources/data/templates/StructureElementCommand_create_systems.xlsx b/src/test/resources/data/templates/StructureElementCommand_create_systems.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..28c5063fd03e1a2477d1abf99c3a20a696fed681 GIT binary patch literal 7499 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 K@FLaC-TwgJjj9m< literal 0 HcmV?d00001 diff --git a/src/test/resources/db/data/templates/NameElementCommand_name_create.xlsx b/src/test/resources/db/data/templates/NameElementCommand_name_create.xlsx deleted file mode 100644 index c9c341a2e84488af7e9877fa1b8afee23cae9f2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7409 zcmaJ`1z1#V)22bXJ0ztWq(P-aX^;?!1y*8V2|+qVknTomK|oLtL>8pGkz7C|rMv6j z)$jl0_5WXIuRYf}*R?ZepP6~?nYkZLHB>ZGBrGf}q)!%FdPp|}2Yzn`2H3ms@glBe zaZL|f_;EwGy}~(<MP}r%-W1lUE7vg!(>Jm>(tLcC*BZ2UBu_$&8~LFn%GuZN%A#Oa z-I05ipH1z_E4|0BQ0mz%eITtpSI(Y%qJ6o(?L=Zq+MoxV;OIxH2fg3#b?1Az#;9Wd z*w;`SLSC`lutJiSdkHqxdoFlo6}BAwc;hv(vyFc4gdZ9-Si`|i#8HKT_Jxelya7`@ zqkE^SdY(5#3`&d#2*viC1^CqVeA`aIr^4k|)*wn|T;A#=AE}9AyiDj>O-Uj7T)PZ* zvN*u#gAxbx+qimZF#9O0Z)KCw37M%z7-e1bER$%eVPb`(38!trozRbhgrxbeZX$sH z!o!~LIS6cL0Rq|adN|leYIixp_zCNexzJ`Ec%D3?NkTQKjzO9sgmk6GDU#cTlXg1W zLw<aDF8>%9el!>)-`{)}WIemLY@)VJ^_tA6jhhyu7d3JHevwaagLHln)jl^^	QK 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 Y*wa))ho>JB5+3|x2+!dlD#X+O0M(jhfdBvi -- GitLab