Add null check to baseurl and improve unit testing, fixes #5789 (#5801)
diff --git a/plugins/transforms/rest/src/main/java/org/apache/hop/pipeline/transforms/rest/Rest.java b/plugins/transforms/rest/src/main/java/org/apache/hop/pipeline/transforms/rest/Rest.java
index aa15fab..d9192fa 100644
--- a/plugins/transforms/rest/src/main/java/org/apache/hop/pipeline/transforms/rest/Rest.java
+++ b/plugins/transforms/rest/src/main/java/org/apache/hop/pipeline/transforms/rest/Rest.java
@@ -17,6 +17,8 @@
package org.apache.hop.pipeline.transforms.rest;
+import static org.apache.hop.core.Const.NVL;
+
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -214,7 +216,7 @@
String entityString = null;
if (data.useBody) {
// Set Http request entity
- entityString = Const.NVL(data.inputRowMeta.getString(rowData, data.indexOfBodyField), null);
+ entityString = NVL(data.inputRowMeta.getString(rowData, data.indexOfBodyField), null);
if (isDebug()) {
logDebug(BaseMessages.getString(PKG, "Rest.Log.BodyValue", entityString));
}
@@ -442,7 +444,7 @@
} else {
// Static URL
if (!Utils.isEmpty(data.connectionName)) {
- data.realUrl = baseUrl + resolve(meta.getUrl());
+ data.realUrl = baseUrl + NVL(resolve(meta.getUrl()), "");
} else {
data.realUrl = resolve(meta.getUrl());
}
@@ -610,7 +612,7 @@
data.trustStoreFile = resolve(meta.getTrustStoreFile());
data.trustStorePassword = resolve(meta.getTrustStorePassword());
- String applicationType = Const.NVL(meta.getApplicationType(), "");
+ String applicationType = NVL(meta.getApplicationType(), "");
if (applicationType.equals(RestMeta.APPLICATION_TYPE_XML)) {
data.mediaType = MediaType.APPLICATION_XML_TYPE;
} else if (applicationType.equals(RestMeta.APPLICATION_TYPE_JSON)) {
diff --git a/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestCallRestTest.java b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestCallRestTest.java
new file mode 100644
index 0000000..b0993dd
--- /dev/null
+++ b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestCallRestTest.java
@@ -0,0 +1,1040 @@
+/*
+ * 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.hop.pipeline.transforms.rest;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import org.apache.hop.core.Const;
+import org.apache.hop.core.encryption.Encr;
+import org.apache.hop.core.encryption.TwoWayPasswordEncoderPluginType;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.logging.HopLogStore;
+import org.apache.hop.core.plugins.PluginRegistry;
+import org.apache.hop.core.row.IRowMeta;
+import org.apache.hop.core.row.RowMeta;
+import org.apache.hop.core.row.value.ValueMetaString;
+import org.apache.hop.core.util.EnvUtil;
+import org.apache.hop.junit.rules.RestoreHopEngineEnvironmentExtension;
+import org.apache.hop.metadata.api.IHopMetadataProvider;
+import org.apache.hop.pipeline.PipelineMeta;
+import org.apache.hop.pipeline.engines.local.LocalPipelineEngine;
+import org.apache.hop.pipeline.transform.TransformMeta;
+import org.apache.hop.pipeline.transforms.rest.fields.HeaderField;
+import org.apache.hop.pipeline.transforms.rest.fields.MatrixParameterField;
+import org.apache.hop.pipeline.transforms.rest.fields.ParameterField;
+import org.apache.hop.pipeline.transforms.rest.fields.ResultField;
+import org.glassfish.jersey.client.ClientConfig;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.mockito.MockedStatic;
+import org.mockito.Mockito;
+
+class RestCallRestTest {
+
+ @RegisterExtension
+ static RestoreHopEngineEnvironmentExtension env = new RestoreHopEngineEnvironmentExtension();
+
+ @BeforeAll
+ static void beforeClass() throws HopException {
+ PluginRegistry.addPluginType(TwoWayPasswordEncoderPluginType.getInstance());
+ PluginRegistry.init();
+ String passwordEncoderPluginID =
+ Const.NVL(EnvUtil.getSystemProperty(Const.HOP_PASSWORD_ENCODER_PLUGIN), "Hop");
+ Encr.init(passwordEncoderPluginID);
+ }
+
+ @BeforeEach
+ void setUp() {
+ if (!HopLogStore.isInitialized()) {
+ HopLogStore.init();
+ }
+ }
+
+ @Test
+ void testCallRestWithGetMethod() throws HopException {
+ // Setup mocks
+ Response response = mock(Response.class);
+ when(response.getStatus()).thenReturn(200);
+ when(response.readEntity(String.class)).thenReturn("{\"result\":\"success\"}");
+ MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
+ headers.add("Content-Type", "application/json");
+ when(response.getHeaders()).thenReturn(headers);
+
+ Invocation.Builder builder = mock(Invocation.Builder.class);
+ when(builder.get(Response.class)).thenReturn(response);
+ when(builder.header(anyString(), any())).thenReturn(builder);
+
+ WebTarget webTarget = mock(WebTarget.class);
+ when(webTarget.request()).thenReturn(builder);
+ when(webTarget.getUri()).thenReturn(URI.create("http://example.com"));
+
+ Client client = mock(Client.class);
+ when(client.target(anyString())).thenReturn(webTarget);
+
+ ClientBuilder clientBuilder = mock(ClientBuilder.class);
+ when(clientBuilder.withConfig(any(ClientConfig.class))).thenReturn(clientBuilder);
+ when(clientBuilder.property(anyString(), any())).thenReturn(clientBuilder);
+ when(clientBuilder.hostnameVerifier(any())).thenReturn(clientBuilder);
+ when(clientBuilder.sslContext(any())).thenReturn(clientBuilder);
+ when(clientBuilder.build()).thenReturn(client);
+
+ try (MockedStatic<ClientBuilder> mockedStatic = Mockito.mockStatic(ClientBuilder.class)) {
+ mockedStatic.when(ClientBuilder::newBuilder).thenReturn(clientBuilder);
+
+ // Setup transform
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_GET);
+ meta.setUrl("http://example.com");
+ meta.setResultField(new ResultField());
+ meta.getResultField().setFieldName("result");
+ meta.getResultField().setCode("statusCode");
+ meta.getResultField().setResponseTime("responseTime");
+ meta.getResultField().setResponseHeader("headers");
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = RestMeta.HTTP_METHOD_GET;
+ data.realUrl = "http://example.com";
+ data.resultFieldName = "result";
+ data.resultCodeFieldName = "statusCode";
+ data.resultResponseFieldName = "responseTime";
+ data.resultHeaderFieldName = "headers";
+
+ // Setup input row
+ IRowMeta inputRowMeta = new RowMeta();
+ inputRowMeta.addValueMeta(new ValueMetaString("field1"));
+ data.inputRowMeta = inputRowMeta;
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 0, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Execute
+ Object[] inputRow = new Object[] {"value1"};
+ Object[] outputRow = rest.callRest(inputRow);
+
+ // Verify
+ assertNotNull(outputRow);
+ // Output row should have at least the input fields plus result fields
+ assertTrue(outputRow.length >= 1);
+ assertEquals("value1", outputRow[0]);
+ // The result fields are added at the end of the input row
+ // Result field is at input size + 0
+ assertEquals("{\"result\":\"success\"}", outputRow[1]); // result field
+ // Status code is at input size + 1
+ assertEquals(200L, outputRow[2]); // status code
+ // Response time is at input size + 2
+ assertNotNull(outputRow[3]); // response time
+ // Headers are at input size + 3
+ assertNotNull(outputRow[4]); // headers
+
+ verify(builder, times(1)).get(Response.class);
+ }
+ }
+
+ @Test
+ void testCallRestWithPostMethod() throws HopException {
+ // Setup mocks
+ Response response = mock(Response.class);
+ when(response.getStatus()).thenReturn(201);
+ when(response.readEntity(String.class)).thenReturn("{\"id\":123}");
+ MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
+ headers.add("Content-Type", "application/json");
+ when(response.getHeaders()).thenReturn(headers);
+
+ Invocation.Builder builder = mock(Invocation.Builder.class);
+ when(builder.post(any(Entity.class))).thenReturn(response);
+ when(builder.header(anyString(), any())).thenReturn(builder);
+
+ WebTarget webTarget = mock(WebTarget.class);
+ when(webTarget.request()).thenReturn(builder);
+ when(webTarget.getUri()).thenReturn(URI.create("http://example.com/api"));
+
+ Client client = mock(Client.class);
+ when(client.target(anyString())).thenReturn(webTarget);
+
+ ClientBuilder clientBuilder = mock(ClientBuilder.class);
+ when(clientBuilder.withConfig(any(ClientConfig.class))).thenReturn(clientBuilder);
+ when(clientBuilder.property(anyString(), any())).thenReturn(clientBuilder);
+ when(clientBuilder.hostnameVerifier(any())).thenReturn(clientBuilder);
+ when(clientBuilder.sslContext(any())).thenReturn(clientBuilder);
+ when(clientBuilder.build()).thenReturn(client);
+
+ try (MockedStatic<ClientBuilder> mockedStatic = Mockito.mockStatic(ClientBuilder.class)) {
+ mockedStatic.when(ClientBuilder::newBuilder).thenReturn(clientBuilder);
+
+ // Setup transform
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_POST);
+ meta.setUrl("http://example.com/api");
+ meta.setBodyField("body");
+ meta.setResultField(new ResultField());
+ meta.getResultField().setFieldName("result");
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = RestMeta.HTTP_METHOD_POST;
+ data.realUrl = "http://example.com/api";
+ data.resultFieldName = "result";
+ data.useBody = true;
+ data.indexOfBodyField = 1;
+
+ // Setup input row
+ IRowMeta inputRowMeta = new RowMeta();
+ inputRowMeta.addValueMeta(new ValueMetaString("field1"));
+ inputRowMeta.addValueMeta(new ValueMetaString("body"));
+ data.inputRowMeta = inputRowMeta;
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 0, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Execute
+ Object[] inputRow = new Object[] {"value1", "{\"name\":\"test\"}"};
+ Object[] outputRow = rest.callRest(inputRow);
+
+ // Verify
+ assertNotNull(outputRow);
+ assertEquals("{\"id\":123}", outputRow[2]); // result field
+ verify(builder, times(1)).post(any(Entity.class));
+ }
+ }
+
+ @Test
+ void testCallRestWithPutMethod() throws HopException {
+ // Setup mocks
+ Response response = mock(Response.class);
+ when(response.getStatus()).thenReturn(200);
+ when(response.readEntity(String.class)).thenReturn("{\"updated\":true}");
+ MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
+ when(response.getHeaders()).thenReturn(headers);
+
+ Invocation.Builder builder = mock(Invocation.Builder.class);
+ when(builder.put(any(Entity.class))).thenReturn(response);
+ when(builder.header(anyString(), any())).thenReturn(builder);
+
+ WebTarget webTarget = mock(WebTarget.class);
+ when(webTarget.request()).thenReturn(builder);
+ when(webTarget.getUri()).thenReturn(URI.create("http://example.com/api"));
+
+ Client client = mock(Client.class);
+ when(client.target(anyString())).thenReturn(webTarget);
+
+ ClientBuilder clientBuilder = mock(ClientBuilder.class);
+ when(clientBuilder.withConfig(any(ClientConfig.class))).thenReturn(clientBuilder);
+ when(clientBuilder.property(anyString(), any())).thenReturn(clientBuilder);
+ when(clientBuilder.hostnameVerifier(any())).thenReturn(clientBuilder);
+ when(clientBuilder.sslContext(any())).thenReturn(clientBuilder);
+ when(clientBuilder.build()).thenReturn(client);
+
+ try (MockedStatic<ClientBuilder> mockedStatic = Mockito.mockStatic(ClientBuilder.class)) {
+ mockedStatic.when(ClientBuilder::newBuilder).thenReturn(clientBuilder);
+
+ // Setup transform
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_PUT);
+ meta.setUrl("http://example.com/api");
+ meta.setBodyField("body");
+ meta.setResultField(new ResultField());
+ meta.getResultField().setFieldName("result");
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = RestMeta.HTTP_METHOD_PUT;
+ data.realUrl = "http://example.com/api";
+ data.resultFieldName = "result";
+ data.useBody = true;
+ data.indexOfBodyField = 0;
+
+ IRowMeta inputRowMeta = new RowMeta();
+ inputRowMeta.addValueMeta(new ValueMetaString("body"));
+ data.inputRowMeta = inputRowMeta;
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 0, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Execute
+ Object[] inputRow = new Object[] {"{\"name\":\"updated\"}"};
+ Object[] outputRow = rest.callRest(inputRow);
+
+ // Verify
+ assertNotNull(outputRow);
+ assertEquals("{\"updated\":true}", outputRow[1]);
+ verify(builder, times(1)).put(any(Entity.class));
+ }
+ }
+
+ @Test
+ void testCallRestWithDeleteMethod() throws HopException {
+ // Setup mocks
+ Response response = mock(Response.class);
+ when(response.getStatus()).thenReturn(204);
+ when(response.readEntity(String.class)).thenReturn("");
+ MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
+ when(response.getHeaders()).thenReturn(headers);
+
+ Invocation invocation = mock(Invocation.class);
+ when(invocation.invoke()).thenReturn(response);
+
+ Invocation.Builder builder = mock(Invocation.Builder.class);
+ when(builder.build(eq("DELETE"), any(Entity.class))).thenReturn(invocation);
+ when(builder.header(anyString(), any())).thenReturn(builder);
+
+ WebTarget webTarget = mock(WebTarget.class);
+ when(webTarget.request()).thenReturn(builder);
+ when(webTarget.getUri()).thenReturn(URI.create("http://example.com/api/123"));
+
+ Client client = mock(Client.class);
+ when(client.target(anyString())).thenReturn(webTarget);
+
+ ClientBuilder clientBuilder = mock(ClientBuilder.class);
+ when(clientBuilder.withConfig(any(ClientConfig.class))).thenReturn(clientBuilder);
+ when(clientBuilder.property(anyString(), any())).thenReturn(clientBuilder);
+ when(clientBuilder.hostnameVerifier(any())).thenReturn(clientBuilder);
+ when(clientBuilder.sslContext(any())).thenReturn(clientBuilder);
+ when(clientBuilder.build()).thenReturn(client);
+
+ try (MockedStatic<ClientBuilder> mockedStatic = Mockito.mockStatic(ClientBuilder.class)) {
+ mockedStatic.when(ClientBuilder::newBuilder).thenReturn(clientBuilder);
+
+ // Setup transform
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_DELETE);
+ meta.setUrl("http://example.com/api/123");
+ meta.setResultField(new ResultField());
+ meta.getResultField().setFieldName("result");
+ meta.getResultField().setCode("statusCode");
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = RestMeta.HTTP_METHOD_DELETE;
+ data.realUrl = "http://example.com/api/123";
+ data.resultFieldName = "result";
+ data.resultCodeFieldName = "statusCode";
+
+ IRowMeta inputRowMeta = new RowMeta();
+ inputRowMeta.addValueMeta(new ValueMetaString("id"));
+ data.inputRowMeta = inputRowMeta;
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 0, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Execute
+ Object[] inputRow = new Object[] {"123"};
+ Object[] outputRow = rest.callRest(inputRow);
+
+ // Verify
+ assertNotNull(outputRow);
+ assertEquals(204L, outputRow[2]); // status code
+ verify(builder, times(1)).build(eq("DELETE"), any(Entity.class));
+ }
+ }
+
+ @Test
+ void testCallRestWithHeadMethod() throws HopException {
+ // Setup mocks
+ Response response = mock(Response.class);
+ when(response.getStatus()).thenReturn(200);
+ when(response.readEntity(String.class)).thenReturn("");
+ MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
+ headers.add("Content-Length", "1234");
+ when(response.getHeaders()).thenReturn(headers);
+
+ Invocation.Builder builder = mock(Invocation.Builder.class);
+ when(builder.head()).thenReturn(response);
+ when(builder.header(anyString(), any())).thenReturn(builder);
+
+ WebTarget webTarget = mock(WebTarget.class);
+ when(webTarget.request()).thenReturn(builder);
+ when(webTarget.getUri()).thenReturn(URI.create("http://example.com/api"));
+
+ Client client = mock(Client.class);
+ when(client.target(anyString())).thenReturn(webTarget);
+
+ ClientBuilder clientBuilder = mock(ClientBuilder.class);
+ when(clientBuilder.withConfig(any(ClientConfig.class))).thenReturn(clientBuilder);
+ when(clientBuilder.property(anyString(), any())).thenReturn(clientBuilder);
+ when(clientBuilder.hostnameVerifier(any())).thenReturn(clientBuilder);
+ when(clientBuilder.sslContext(any())).thenReturn(clientBuilder);
+ when(clientBuilder.build()).thenReturn(client);
+
+ try (MockedStatic<ClientBuilder> mockedStatic = Mockito.mockStatic(ClientBuilder.class)) {
+ mockedStatic.when(ClientBuilder::newBuilder).thenReturn(clientBuilder);
+
+ // Setup transform
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_HEAD);
+ meta.setUrl("http://example.com/api");
+ meta.setResultField(new ResultField());
+ meta.getResultField().setCode("statusCode");
+ meta.getResultField().setResponseHeader("headers");
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = RestMeta.HTTP_METHOD_HEAD;
+ data.realUrl = "http://example.com/api";
+ data.resultCodeFieldName = "statusCode";
+ data.resultHeaderFieldName = "headers";
+
+ IRowMeta inputRowMeta = new RowMeta();
+ data.inputRowMeta = inputRowMeta;
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 0, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Execute
+ Object[] inputRow = new Object[] {};
+ Object[] outputRow = rest.callRest(inputRow);
+
+ // Verify
+ assertNotNull(outputRow);
+ assertEquals(200L, outputRow[0]); // status code
+ verify(builder, times(1)).head();
+ }
+ }
+
+ @Test
+ void testCallRestWithOptionsMethod() throws HopException {
+ // Setup mocks
+ Response response = mock(Response.class);
+ when(response.getStatus()).thenReturn(200);
+ when(response.readEntity(String.class)).thenReturn("");
+ MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
+ headers.add("Allow", "GET, POST, PUT, DELETE");
+ when(response.getHeaders()).thenReturn(headers);
+
+ Invocation.Builder builder = mock(Invocation.Builder.class);
+ when(builder.options()).thenReturn(response);
+ when(builder.header(anyString(), any())).thenReturn(builder);
+
+ WebTarget webTarget = mock(WebTarget.class);
+ when(webTarget.request()).thenReturn(builder);
+ when(webTarget.getUri()).thenReturn(URI.create("http://example.com/api"));
+
+ Client client = mock(Client.class);
+ when(client.target(anyString())).thenReturn(webTarget);
+
+ ClientBuilder clientBuilder = mock(ClientBuilder.class);
+ when(clientBuilder.withConfig(any(ClientConfig.class))).thenReturn(clientBuilder);
+ when(clientBuilder.property(anyString(), any())).thenReturn(clientBuilder);
+ when(clientBuilder.hostnameVerifier(any())).thenReturn(clientBuilder);
+ when(clientBuilder.sslContext(any())).thenReturn(clientBuilder);
+ when(clientBuilder.build()).thenReturn(client);
+
+ try (MockedStatic<ClientBuilder> mockedStatic = Mockito.mockStatic(ClientBuilder.class)) {
+ mockedStatic.when(ClientBuilder::newBuilder).thenReturn(clientBuilder);
+
+ // Setup transform
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_OPTIONS);
+ meta.setUrl("http://example.com/api");
+ meta.setResultField(new ResultField());
+ meta.getResultField().setResponseHeader("allowedMethods");
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = RestMeta.HTTP_METHOD_OPTIONS;
+ data.realUrl = "http://example.com/api";
+ data.resultHeaderFieldName = "allowedMethods";
+
+ IRowMeta inputRowMeta = new RowMeta();
+ data.inputRowMeta = inputRowMeta;
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 0, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Execute
+ Object[] inputRow = new Object[] {};
+ Object[] outputRow = rest.callRest(inputRow);
+
+ // Verify
+ assertNotNull(outputRow);
+ verify(builder, times(1)).options();
+ }
+ }
+
+ @Test
+ void testCallRestWithPatchMethod() throws HopException {
+ // Setup mocks
+ Response response = mock(Response.class);
+ when(response.getStatus()).thenReturn(200);
+ when(response.readEntity(String.class)).thenReturn("{\"patched\":true}");
+ MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
+ when(response.getHeaders()).thenReturn(headers);
+
+ Invocation.Builder builder = mock(Invocation.Builder.class);
+ when(builder.method(eq(RestMeta.HTTP_METHOD_PATCH), any(Entity.class))).thenReturn(response);
+ when(builder.header(anyString(), any())).thenReturn(builder);
+
+ WebTarget webTarget = mock(WebTarget.class);
+ when(webTarget.request()).thenReturn(builder);
+ when(webTarget.getUri()).thenReturn(URI.create("http://example.com/api"));
+
+ Client client = mock(Client.class);
+ when(client.target(anyString())).thenReturn(webTarget);
+
+ ClientBuilder clientBuilder = mock(ClientBuilder.class);
+ when(clientBuilder.withConfig(any(ClientConfig.class))).thenReturn(clientBuilder);
+ when(clientBuilder.property(anyString(), any())).thenReturn(clientBuilder);
+ when(clientBuilder.hostnameVerifier(any())).thenReturn(clientBuilder);
+ when(clientBuilder.sslContext(any())).thenReturn(clientBuilder);
+ when(clientBuilder.build()).thenReturn(client);
+
+ try (MockedStatic<ClientBuilder> mockedStatic = Mockito.mockStatic(ClientBuilder.class)) {
+ mockedStatic.when(ClientBuilder::newBuilder).thenReturn(clientBuilder);
+
+ // Setup transform
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_PATCH);
+ meta.setUrl("http://example.com/api");
+ meta.setBodyField("body");
+ meta.setResultField(new ResultField());
+ meta.getResultField().setFieldName("result");
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = RestMeta.HTTP_METHOD_PATCH;
+ data.realUrl = "http://example.com/api";
+ data.resultFieldName = "result";
+ data.useBody = true;
+ data.indexOfBodyField = 0;
+
+ IRowMeta inputRowMeta = new RowMeta();
+ inputRowMeta.addValueMeta(new ValueMetaString("body"));
+ data.inputRowMeta = inputRowMeta;
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 0, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Execute
+ Object[] inputRow = new Object[] {"{\"field\":\"value\"}"};
+ Object[] outputRow = rest.callRest(inputRow);
+
+ // Verify
+ assertNotNull(outputRow);
+ assertEquals("{\"patched\":true}", outputRow[1]);
+ verify(builder, times(1)).method(eq(RestMeta.HTTP_METHOD_PATCH), any(Entity.class));
+ }
+ }
+
+ @Test
+ void testCallRestWithQueryParameters() throws HopException {
+ // Setup mocks
+ Response response = mock(Response.class);
+ when(response.getStatus()).thenReturn(200);
+ when(response.readEntity(String.class)).thenReturn("[{\"id\":1},{\"id\":2}]");
+ MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
+ when(response.getHeaders()).thenReturn(headers);
+
+ Invocation.Builder builder = mock(Invocation.Builder.class);
+ when(builder.get(Response.class)).thenReturn(response);
+ when(builder.header(anyString(), any())).thenReturn(builder);
+
+ WebTarget webTarget = mock(WebTarget.class);
+ when(webTarget.request()).thenReturn(builder);
+ when(webTarget.queryParam(anyString(), any())).thenReturn(webTarget);
+ when(webTarget.getUri()).thenReturn(URI.create("http://example.com/api?search=test&limit=10"));
+
+ Client client = mock(Client.class);
+ when(client.target(anyString())).thenReturn(webTarget);
+
+ ClientBuilder clientBuilder = mock(ClientBuilder.class);
+ when(clientBuilder.withConfig(any(ClientConfig.class))).thenReturn(clientBuilder);
+ when(clientBuilder.property(anyString(), any())).thenReturn(clientBuilder);
+ when(clientBuilder.hostnameVerifier(any())).thenReturn(clientBuilder);
+ when(clientBuilder.sslContext(any())).thenReturn(clientBuilder);
+ when(clientBuilder.build()).thenReturn(client);
+
+ try (MockedStatic<ClientBuilder> mockedStatic = Mockito.mockStatic(ClientBuilder.class)) {
+ mockedStatic.when(ClientBuilder::newBuilder).thenReturn(clientBuilder);
+
+ // Setup transform
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_GET);
+ meta.setUrl("http://example.com/api");
+ List<ParameterField> params = new ArrayList<>();
+ params.add(new ParameterField("searchField", "search"));
+ params.add(new ParameterField("limitField", "limit"));
+ meta.setParameterFields(params);
+ meta.setResultField(new ResultField());
+ meta.getResultField().setFieldName("result");
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = RestMeta.HTTP_METHOD_GET;
+ data.realUrl = "http://example.com/api";
+ data.resultFieldName = "result";
+ data.useParams = true;
+ data.nrParams = 2;
+ data.paramNames = new String[] {"search", "limit"};
+ data.indexOfParamFields = new int[] {0, 1};
+
+ IRowMeta inputRowMeta = new RowMeta();
+ inputRowMeta.addValueMeta(new ValueMetaString("searchField"));
+ inputRowMeta.addValueMeta(new ValueMetaString("limitField"));
+ data.inputRowMeta = inputRowMeta;
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 0, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Execute
+ Object[] inputRow = new Object[] {"test", "10"};
+ Object[] outputRow = rest.callRest(inputRow);
+
+ // Verify
+ assertNotNull(outputRow);
+ assertEquals("[{\"id\":1},{\"id\":2}]", outputRow[2]);
+ verify(webTarget, times(2)).queryParam(anyString(), any());
+ }
+ }
+
+ @Test
+ void testCallRestWithHeaders() throws HopException {
+ // Setup mocks
+ Response response = mock(Response.class);
+ when(response.getStatus()).thenReturn(200);
+ when(response.readEntity(String.class)).thenReturn("{\"authenticated\":true}");
+ MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
+ when(response.getHeaders()).thenReturn(headers);
+
+ Invocation.Builder builder = mock(Invocation.Builder.class);
+ when(builder.get(Response.class)).thenReturn(response);
+ when(builder.header(anyString(), any())).thenReturn(builder);
+
+ WebTarget webTarget = mock(WebTarget.class);
+ when(webTarget.request()).thenReturn(builder);
+ when(webTarget.getUri()).thenReturn(URI.create("http://example.com/api"));
+
+ Client client = mock(Client.class);
+ when(client.target(anyString())).thenReturn(webTarget);
+
+ ClientBuilder clientBuilder = mock(ClientBuilder.class);
+ when(clientBuilder.withConfig(any(ClientConfig.class))).thenReturn(clientBuilder);
+ when(clientBuilder.property(anyString(), any())).thenReturn(clientBuilder);
+ when(clientBuilder.hostnameVerifier(any())).thenReturn(clientBuilder);
+ when(clientBuilder.sslContext(any())).thenReturn(clientBuilder);
+ when(clientBuilder.build()).thenReturn(client);
+
+ try (MockedStatic<ClientBuilder> mockedStatic = Mockito.mockStatic(ClientBuilder.class)) {
+ mockedStatic.when(ClientBuilder::newBuilder).thenReturn(clientBuilder);
+
+ // Setup transform
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_GET);
+ meta.setUrl("http://example.com/api");
+ List<HeaderField> headerFields = new ArrayList<>();
+ headerFields.add(new HeaderField("authField", "Authorization"));
+ headerFields.add(new HeaderField("typeField", "Content-Type"));
+ meta.setHeaderFields(headerFields);
+ meta.setResultField(new ResultField());
+ meta.getResultField().setFieldName("result");
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = RestMeta.HTTP_METHOD_GET;
+ data.realUrl = "http://example.com/api";
+ data.resultFieldName = "result";
+ data.useHeaders = true;
+ data.nrheader = 2;
+ data.headerNames = new String[] {"Authorization", "Content-Type"};
+ data.indexOfHeaderFields = new int[] {0, 1};
+
+ IRowMeta inputRowMeta = new RowMeta();
+ inputRowMeta.addValueMeta(new ValueMetaString("authField"));
+ inputRowMeta.addValueMeta(new ValueMetaString("typeField"));
+ data.inputRowMeta = inputRowMeta;
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 0, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Execute
+ Object[] inputRow = new Object[] {"Bearer token123", "application/json"};
+ Object[] outputRow = rest.callRest(inputRow);
+
+ // Verify
+ assertNotNull(outputRow);
+ assertEquals("{\"authenticated\":true}", outputRow[2]);
+ verify(builder, times(2)).header(anyString(), any());
+ }
+ }
+
+ @Test
+ void testCallRestWithMatrixParameters() throws HopException {
+ // Setup mocks
+ Response response = mock(Response.class);
+ when(response.getStatus()).thenReturn(200);
+ when(response.readEntity(String.class)).thenReturn("[{\"book\":\"title\"}]");
+ MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
+ when(response.getHeaders()).thenReturn(headers);
+
+ Invocation.Builder builder = mock(Invocation.Builder.class);
+ when(builder.get(Response.class)).thenReturn(response);
+ when(builder.header(anyString(), any())).thenReturn(builder);
+
+ WebTarget webTarget = mock(WebTarget.class);
+ when(webTarget.request()).thenReturn(builder);
+ when(webTarget.getUri()).thenReturn(URI.create("http://example.com/api"));
+ when(webTarget.getUriBuilder()).thenReturn(UriBuilder.fromUri("http://example.com/api"));
+
+ Client client = mock(Client.class);
+ when(client.target(anyString())).thenReturn(webTarget);
+ when(client.target(any(URI.class))).thenReturn(webTarget);
+
+ ClientBuilder clientBuilder = mock(ClientBuilder.class);
+ when(clientBuilder.withConfig(any(ClientConfig.class))).thenReturn(clientBuilder);
+ when(clientBuilder.property(anyString(), any())).thenReturn(clientBuilder);
+ when(clientBuilder.hostnameVerifier(any())).thenReturn(clientBuilder);
+ when(clientBuilder.sslContext(any())).thenReturn(clientBuilder);
+ when(clientBuilder.build()).thenReturn(client);
+
+ try (MockedStatic<ClientBuilder> mockedStatic = Mockito.mockStatic(ClientBuilder.class)) {
+ mockedStatic.when(ClientBuilder::newBuilder).thenReturn(clientBuilder);
+
+ // Setup transform
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_GET);
+ meta.setUrl("http://example.com/api");
+ List<MatrixParameterField> matrixParams = new ArrayList<>();
+ matrixParams.add(new MatrixParameterField("authorField", "author"));
+ matrixParams.add(new MatrixParameterField("yearField", "year"));
+ meta.setMatrixParameterFields(matrixParams);
+ meta.setResultField(new ResultField());
+ meta.getResultField().setFieldName("result");
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = RestMeta.HTTP_METHOD_GET;
+ data.realUrl = "http://example.com/api";
+ data.resultFieldName = "result";
+ data.useMatrixParams = true;
+ data.nrMatrixParams = 2;
+ data.matrixParamNames = new String[] {"author", "year"};
+ data.indexOfMatrixParamFields = new int[] {0, 1};
+
+ IRowMeta inputRowMeta = new RowMeta();
+ inputRowMeta.addValueMeta(new ValueMetaString("authorField"));
+ inputRowMeta.addValueMeta(new ValueMetaString("yearField"));
+ data.inputRowMeta = inputRowMeta;
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 0, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Execute
+ Object[] inputRow = new Object[] {"John Doe", "2023"};
+ Object[] outputRow = rest.callRest(inputRow);
+
+ // Verify
+ assertNotNull(outputRow);
+ assertEquals("[{\"book\":\"title\"}]", outputRow[2]);
+ }
+ }
+
+ @Test
+ void testCallRestWithDynamicUrl() throws HopException {
+ // Setup mocks
+ Response response = mock(Response.class);
+ when(response.getStatus()).thenReturn(200);
+ when(response.readEntity(String.class)).thenReturn("{\"dynamic\":true}");
+ MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
+ when(response.getHeaders()).thenReturn(headers);
+
+ Invocation.Builder builder = mock(Invocation.Builder.class);
+ when(builder.get(Response.class)).thenReturn(response);
+ when(builder.header(anyString(), any())).thenReturn(builder);
+
+ WebTarget webTarget = mock(WebTarget.class);
+ when(webTarget.request()).thenReturn(builder);
+ when(webTarget.getUri()).thenReturn(URI.create("http://dynamic-url.com/api/resource"));
+
+ Client client = mock(Client.class);
+ when(client.target(anyString())).thenReturn(webTarget);
+
+ ClientBuilder clientBuilder = mock(ClientBuilder.class);
+ when(clientBuilder.withConfig(any(ClientConfig.class))).thenReturn(clientBuilder);
+ when(clientBuilder.property(anyString(), any())).thenReturn(clientBuilder);
+ when(clientBuilder.hostnameVerifier(any())).thenReturn(clientBuilder);
+ when(clientBuilder.sslContext(any())).thenReturn(clientBuilder);
+ when(clientBuilder.build()).thenReturn(client);
+
+ try (MockedStatic<ClientBuilder> mockedStatic = Mockito.mockStatic(ClientBuilder.class)) {
+ mockedStatic.when(ClientBuilder::newBuilder).thenReturn(clientBuilder);
+
+ // Setup transform
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_GET);
+ meta.setUrlInField(true);
+ meta.setUrlField("urlField");
+ meta.setResultField(new ResultField());
+ meta.getResultField().setFieldName("result");
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = RestMeta.HTTP_METHOD_GET;
+ data.resultFieldName = "result";
+ data.indexOfUrlField = 0;
+
+ IRowMeta inputRowMeta = new RowMeta();
+ inputRowMeta.addValueMeta(new ValueMetaString("urlField"));
+ data.inputRowMeta = inputRowMeta;
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 0, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Execute
+ Object[] inputRow = new Object[] {"http://dynamic-url.com/api/resource"};
+ Object[] outputRow = rest.callRest(inputRow);
+
+ // Verify
+ assertNotNull(outputRow);
+ assertEquals("{\"dynamic\":true}", outputRow[1]);
+ }
+ }
+
+ @Test
+ void testCallRestWithDynamicMethod() throws HopException {
+ // Setup mocks
+ Response response = mock(Response.class);
+ when(response.getStatus()).thenReturn(201);
+ when(response.readEntity(String.class)).thenReturn("{\"created\":true}");
+ MultivaluedMap<String, Object> headers = new MultivaluedHashMap<>();
+ when(response.getHeaders()).thenReturn(headers);
+
+ Invocation.Builder builder = mock(Invocation.Builder.class);
+ when(builder.post(any(Entity.class))).thenReturn(response);
+ when(builder.header(anyString(), any())).thenReturn(builder);
+
+ WebTarget webTarget = mock(WebTarget.class);
+ when(webTarget.request()).thenReturn(builder);
+ when(webTarget.getUri()).thenReturn(URI.create("http://example.com/api"));
+
+ Client client = mock(Client.class);
+ when(client.target(anyString())).thenReturn(webTarget);
+
+ ClientBuilder clientBuilder = mock(ClientBuilder.class);
+ when(clientBuilder.withConfig(any(ClientConfig.class))).thenReturn(clientBuilder);
+ when(clientBuilder.property(anyString(), any())).thenReturn(clientBuilder);
+ when(clientBuilder.hostnameVerifier(any())).thenReturn(clientBuilder);
+ when(clientBuilder.sslContext(any())).thenReturn(clientBuilder);
+ when(clientBuilder.build()).thenReturn(client);
+
+ try (MockedStatic<ClientBuilder> mockedStatic = Mockito.mockStatic(ClientBuilder.class)) {
+ mockedStatic.when(ClientBuilder::newBuilder).thenReturn(clientBuilder);
+
+ // Setup transform
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setDynamicMethod(true);
+ meta.setMethodFieldName("methodField");
+ meta.setUrl("http://example.com/api");
+ meta.setResultField(new ResultField());
+ meta.getResultField().setFieldName("result");
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.realUrl = "http://example.com/api";
+ data.resultFieldName = "result";
+ data.indexOfMethod = 0;
+
+ IRowMeta inputRowMeta = new RowMeta();
+ inputRowMeta.addValueMeta(new ValueMetaString("methodField"));
+ data.inputRowMeta = inputRowMeta;
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 0, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Execute
+ Object[] inputRow = new Object[] {"POST"};
+ Object[] outputRow = rest.callRest(inputRow);
+
+ // Verify
+ assertNotNull(outputRow);
+ assertEquals("{\"created\":true}", outputRow[1]);
+ }
+ }
+
+ @Test
+ void testCallRestWithUnknownMethod() throws Exception {
+ // Setup transform
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setUrl("http://example.com/api");
+ meta.setResultField(new ResultField());
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = "INVALID_METHOD";
+ data.realUrl = "http://example.com/api";
+
+ IRowMeta inputRowMeta = new RowMeta();
+ data.inputRowMeta = inputRowMeta;
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 0, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // This should throw an exception for unknown method
+ // We'll need to mock the client builder even for the error case
+ ClientBuilder clientBuilder = mock(ClientBuilder.class);
+ when(clientBuilder.withConfig(any(ClientConfig.class))).thenReturn(clientBuilder);
+ when(clientBuilder.property(anyString(), any())).thenReturn(clientBuilder);
+ when(clientBuilder.hostnameVerifier(any())).thenReturn(clientBuilder);
+ when(clientBuilder.sslContext(any())).thenReturn(clientBuilder);
+
+ Client client = mock(Client.class);
+ WebTarget webTarget = mock(WebTarget.class);
+ when(client.target(anyString())).thenReturn(webTarget);
+ when(webTarget.getUri()).thenReturn(URI.create("http://example.com/api"));
+ Invocation.Builder builder = mock(Invocation.Builder.class);
+ when(webTarget.request()).thenReturn(builder);
+ when(builder.header(anyString(), any())).thenReturn(builder);
+ when(clientBuilder.build()).thenReturn(client);
+
+ try (MockedStatic<ClientBuilder> mockedStatic = Mockito.mockStatic(ClientBuilder.class)) {
+ mockedStatic.when(ClientBuilder::newBuilder).thenReturn(clientBuilder);
+
+ // Execute and expect exception
+ Object[] inputRow = new Object[] {};
+ assertThrows(HopException.class, () -> rest.callRest(inputRow));
+ }
+ }
+}
diff --git a/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestDataTest.java b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestDataTest.java
new file mode 100644
index 0000000..bd7c3c7
--- /dev/null
+++ b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestDataTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.hop.pipeline.transforms.rest;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.Test;
+
+class RestDataTest {
+
+ @Test
+ void testDefaultConstructor() {
+ RestData data = new RestData();
+ assertNotNull(data);
+ assertEquals(-1, data.indexOfUrlField);
+ assertNull(data.realProxyHost);
+ assertEquals(8080, data.realProxyPort);
+ assertNull(data.realHttpLogin);
+ assertNull(data.realHttpPassword);
+ assertNull(data.resultFieldName);
+ assertNull(data.resultCodeFieldName);
+ assertNull(data.resultResponseFieldName);
+ assertNull(data.resultHeaderFieldName);
+ assertEquals(0, data.nrParams);
+ assertEquals(0, data.nrMatrixParams);
+ assertNull(data.method);
+ assertEquals(-1, data.indexOfBodyField);
+ assertEquals(-1, data.indexOfMethod);
+ assertNull(data.config);
+ assertNull(data.trustStoreFile);
+ assertNull(data.trustStorePassword);
+ assertNull(data.basicAuthentication);
+ assertNull(data.sslContext);
+ }
+
+ @Test
+ void testFieldAssignments() {
+ RestData data = new RestData();
+
+ data.indexOfUrlField = 5;
+ data.realUrl = "http://example.com";
+ data.method = "GET";
+ data.realConnectionTimeout = 5000;
+ data.realReadTimeout = 10000;
+ data.indexOfMethod = 2;
+ data.nrheader = 3;
+ data.nrParams = 4;
+ data.nrMatrixParams = 2;
+ data.realProxyHost = "proxy.example.com";
+ data.realProxyPort = 8888;
+ data.realHttpLogin = "user";
+ data.realHttpPassword = "pass";
+ data.resultFieldName = "result";
+ data.resultCodeFieldName = "code";
+ data.resultResponseFieldName = "responseTime";
+ data.resultHeaderFieldName = "headers";
+ data.useHeaders = true;
+ data.useParams = true;
+ data.useMatrixParams = true;
+ data.useBody = true;
+ data.indexOfBodyField = 7;
+ data.trustStoreFile = "/path/to/truststore";
+ data.trustStorePassword = "trustpass";
+
+ assertEquals(5, data.indexOfUrlField);
+ assertEquals("http://example.com", data.realUrl);
+ assertEquals("GET", data.method);
+ assertEquals(5000, data.realConnectionTimeout);
+ assertEquals(10000, data.realReadTimeout);
+ assertEquals(2, data.indexOfMethod);
+ assertEquals(3, data.nrheader);
+ assertEquals(4, data.nrParams);
+ assertEquals(2, data.nrMatrixParams);
+ assertEquals("proxy.example.com", data.realProxyHost);
+ assertEquals(8888, data.realProxyPort);
+ assertEquals("user", data.realHttpLogin);
+ assertEquals("pass", data.realHttpPassword);
+ assertEquals("result", data.resultFieldName);
+ assertEquals("code", data.resultCodeFieldName);
+ assertEquals("responseTime", data.resultResponseFieldName);
+ assertEquals("headers", data.resultHeaderFieldName);
+ assertEquals(true, data.useHeaders);
+ assertEquals(true, data.useParams);
+ assertEquals(true, data.useMatrixParams);
+ assertEquals(true, data.useBody);
+ assertEquals(7, data.indexOfBodyField);
+ assertEquals("/path/to/truststore", data.trustStoreFile);
+ assertEquals("trustpass", data.trustStorePassword);
+ }
+
+ @Test
+ void testDefaultBooleanValues() {
+ RestData data = new RestData();
+ assertFalse(data.useHeaders);
+ assertFalse(data.useParams);
+ assertFalse(data.useMatrixParams);
+ assertFalse(data.useBody);
+ }
+}
diff --git a/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestInitAndProcessTest.java b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestInitAndProcessTest.java
new file mode 100644
index 0000000..3824596
--- /dev/null
+++ b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestInitAndProcessTest.java
@@ -0,0 +1,340 @@
+/*
+ * 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.hop.pipeline.transforms.rest;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+
+import javax.ws.rs.core.MediaType;
+import org.apache.hop.core.Const;
+import org.apache.hop.core.encryption.Encr;
+import org.apache.hop.core.encryption.TwoWayPasswordEncoderPluginType;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.logging.HopLogStore;
+import org.apache.hop.core.plugins.PluginRegistry;
+import org.apache.hop.core.util.EnvUtil;
+import org.apache.hop.junit.rules.RestoreHopEngineEnvironmentExtension;
+import org.apache.hop.metadata.api.IHopMetadataProvider;
+import org.apache.hop.pipeline.PipelineMeta;
+import org.apache.hop.pipeline.engines.local.LocalPipelineEngine;
+import org.apache.hop.pipeline.transform.TransformMeta;
+import org.apache.hop.pipeline.transforms.rest.fields.ResultField;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+class RestInitAndProcessTest {
+
+ @RegisterExtension
+ static RestoreHopEngineEnvironmentExtension env = new RestoreHopEngineEnvironmentExtension();
+
+ @BeforeAll
+ static void beforeClass() throws HopException {
+ PluginRegistry.addPluginType(TwoWayPasswordEncoderPluginType.getInstance());
+ PluginRegistry.init();
+ String passwordEncoderPluginID =
+ Const.NVL(EnvUtil.getSystemProperty(Const.HOP_PASSWORD_ENCODER_PLUGIN), "Hop");
+ Encr.init(passwordEncoderPluginID);
+ }
+
+ @BeforeEach
+ void setUp() {
+ // Ensure HopLogStore is initialized before each test
+ if (!HopLogStore.isInitialized()) {
+ HopLogStore.init();
+ }
+ }
+
+ @Test
+ void testInitWithStaticMethod() {
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_GET);
+ meta.setUrl("http://example.com");
+ meta.setApplicationType(RestMeta.APPLICATION_TYPE_JSON);
+ meta.setConnectionTimeout("5000");
+ meta.setReadTimeout("10000");
+ meta.setResultField(new ResultField());
+ meta.getResultField().setFieldName("result");
+ meta.getResultField().setCode("statusCode");
+ meta.getResultField().setResponseTime("responseTime");
+ meta.getResultField().setResponseHeader("headers");
+
+ RestData data = new RestData();
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 1, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ boolean result = rest.init();
+
+ assertTrue(result);
+ assertEquals("result", data.resultFieldName);
+ assertEquals("statusCode", data.resultCodeFieldName);
+ assertEquals("responseTime", data.resultResponseFieldName);
+ assertEquals("headers", data.resultHeaderFieldName);
+ assertEquals(5000, data.realConnectionTimeout);
+ assertEquals(10000, data.realReadTimeout);
+ assertEquals(RestMeta.HTTP_METHOD_GET, data.method);
+ assertNotNull(data.config);
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, data.mediaType);
+ }
+
+ @Test
+ void testInitWithDynamicMethod() {
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setDynamicMethod(true);
+ meta.setMethodFieldName("methodField");
+ meta.setUrl("http://example.com");
+ meta.setApplicationType(RestMeta.APPLICATION_TYPE_XML);
+ meta.setConnectionTimeout("3000");
+ meta.setReadTimeout("6000");
+ meta.setResultField(new ResultField());
+
+ RestData data = new RestData();
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 1, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ boolean result = rest.init();
+
+ assertTrue(result);
+ assertEquals(3000, data.realConnectionTimeout);
+ assertEquals(6000, data.realReadTimeout);
+ assertEquals(MediaType.APPLICATION_XML_TYPE, data.mediaType);
+ }
+
+ @Test
+ void testInitWithMissingStaticMethod() {
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setDynamicMethod(false);
+ // Don't set method
+ meta.setUrl("http://example.com");
+ meta.setResultField(new ResultField());
+
+ RestData data = new RestData();
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 1, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ boolean result = rest.init();
+
+ assertFalse(result);
+ }
+
+ @Test
+ void testInitWithProxySettings() {
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_POST);
+ meta.setUrl("http://example.com");
+ meta.setProxyHost("proxy.example.com");
+ meta.setProxyPort("8080");
+ meta.setHttpLogin("user");
+ meta.setHttpPassword("password");
+ meta.setResultField(new ResultField());
+
+ RestData data = new RestData();
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 1, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ boolean result = rest.init();
+
+ assertTrue(result);
+ assertEquals("proxy.example.com", data.realProxyHost);
+ assertEquals(8080, data.realProxyPort);
+ assertEquals("user", data.realHttpLogin);
+ assertNotNull(data.realHttpPassword);
+ assertNotNull(data.basicAuthentication);
+ }
+
+ @Test
+ void testInitWithAllApplicationTypes() {
+ for (String appType : RestMeta.APPLICATION_TYPES) {
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_GET);
+ meta.setUrl("http://example.com");
+ meta.setApplicationType(appType);
+ meta.setResultField(new ResultField());
+
+ RestData data = new RestData();
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 1, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ boolean result = rest.init();
+
+ assertTrue(result);
+ assertNotNull(data.mediaType);
+
+ // Verify correct media type is set based on application type
+ switch (appType) {
+ case RestMeta.APPLICATION_TYPE_XML:
+ assertEquals(MediaType.APPLICATION_XML_TYPE, data.mediaType);
+ break;
+ case RestMeta.APPLICATION_TYPE_JSON:
+ assertEquals(MediaType.APPLICATION_JSON_TYPE, data.mediaType);
+ break;
+ case RestMeta.APPLICATION_TYPE_OCTET_STREAM:
+ assertEquals(MediaType.APPLICATION_OCTET_STREAM_TYPE, data.mediaType);
+ break;
+ case RestMeta.APPLICATION_TYPE_XHTML:
+ assertEquals(MediaType.APPLICATION_XHTML_XML_TYPE, data.mediaType);
+ break;
+ case RestMeta.APPLICATION_TYPE_FORM_URLENCODED:
+ assertEquals(MediaType.APPLICATION_FORM_URLENCODED_TYPE, data.mediaType);
+ break;
+ case RestMeta.APPLICATION_TYPE_ATOM_XML:
+ assertEquals(MediaType.APPLICATION_ATOM_XML_TYPE, data.mediaType);
+ break;
+ case RestMeta.APPLICATION_TYPE_SVG_XML:
+ assertEquals(MediaType.APPLICATION_SVG_XML_TYPE, data.mediaType);
+ break;
+ case RestMeta.APPLICATION_TYPE_TEXT_XML:
+ assertEquals(MediaType.TEXT_XML_TYPE, data.mediaType);
+ break;
+ case RestMeta.APPLICATION_TYPE_TEXT_PLAIN:
+ default:
+ assertEquals(MediaType.TEXT_PLAIN_TYPE, data.mediaType);
+ break;
+ }
+ }
+ }
+
+ @Test
+ void testInitWithIgnoreSsl() {
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_GET);
+ meta.setUrl("https://example.com");
+ meta.setIgnoreSsl(true);
+ meta.setResultField(new ResultField());
+
+ RestData data = new RestData();
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 1, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ boolean result = rest.init();
+
+ assertTrue(result);
+ assertNotNull(data.sslContext);
+ }
+
+ @Test
+ void testInitWithDefaultTimeouts() {
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_GET);
+ meta.setUrl("http://example.com");
+ // Don't set timeouts, should use defaults
+ meta.setResultField(new ResultField());
+
+ RestData data = new RestData();
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 1, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ boolean result = rest.init();
+
+ assertTrue(result);
+ assertEquals(-1, data.realConnectionTimeout);
+ assertEquals(-1, data.realReadTimeout);
+ }
+
+ @Test
+ void testInitWithVariables() {
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_GET);
+ meta.setUrl("${BASE_URL}/api");
+ meta.setConnectionTimeout("${CONN_TIMEOUT}");
+ meta.setReadTimeout("${READ_TIMEOUT}");
+ meta.setResultField(new ResultField());
+
+ RestData data = new RestData();
+
+ Rest rest =
+ new Rest(transformMeta, meta, data, 1, pipelineMeta, spy(new LocalPipelineEngine()));
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+ rest.setVariable("BASE_URL", "http://example.com");
+ rest.setVariable("CONN_TIMEOUT", "3000");
+ rest.setVariable("READ_TIMEOUT", "7000");
+
+ boolean result = rest.init();
+
+ assertTrue(result);
+ assertEquals(3000, data.realConnectionTimeout);
+ assertEquals(7000, data.realReadTimeout);
+ }
+}
diff --git a/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestMetaTest.java b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestMetaTest.java
index d84b770..a70d8f1 100644
--- a/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestMetaTest.java
+++ b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestMetaTest.java
@@ -17,7 +17,10 @@
package org.apache.hop.pipeline.transforms.rest;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+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.util.ArrayList;
@@ -57,7 +60,7 @@
class RestMetaTest implements IInitializer<ITransformMeta> {
- LoadSaveTester loadSaveTester;
+ LoadSaveTester<RestMeta> loadSaveTester;
Class<RestMeta> testMetaClass = RestMeta.class;
@RegisterExtension
@@ -73,6 +76,7 @@
}
@Test
+ @SuppressWarnings({"rawtypes", "unchecked"})
void testLoadSaveRoundTrip() throws HopException {
List<String> attributes =
Arrays.asList(
@@ -294,6 +298,190 @@
assertFalse(RestMeta.isActiveBody(RestMeta.HTTP_METHOD_OPTIONS));
}
+ @Test
+ void testIsActiveBodyWithEmptyMethod() {
+ assertFalse(RestMeta.isActiveBody(""));
+ assertFalse(RestMeta.isActiveBody(null));
+ }
+
+ @Test
+ void testIsActiveParametersForAllMethods() {
+ assertTrue(RestMeta.isActiveParameters(RestMeta.HTTP_METHOD_GET));
+ assertTrue(RestMeta.isActiveParameters(RestMeta.HTTP_METHOD_POST));
+ assertTrue(RestMeta.isActiveParameters(RestMeta.HTTP_METHOD_PUT));
+ assertTrue(RestMeta.isActiveParameters(RestMeta.HTTP_METHOD_PATCH));
+ assertTrue(RestMeta.isActiveParameters(RestMeta.HTTP_METHOD_DELETE));
+
+ assertFalse(RestMeta.isActiveParameters(RestMeta.HTTP_METHOD_HEAD));
+ assertFalse(RestMeta.isActiveParameters(RestMeta.HTTP_METHOD_OPTIONS));
+ }
+
+ @Test
+ void testIsActiveParametersWithEmptyMethod() {
+ assertFalse(RestMeta.isActiveParameters(""));
+ assertFalse(RestMeta.isActiveParameters(null));
+ }
+
+ @Test
+ void testClone() {
+ RestMeta meta = new RestMeta();
+ meta.setUrl("http://example.com");
+ meta.setMethod(RestMeta.HTTP_METHOD_POST);
+ meta.setApplicationType(RestMeta.APPLICATION_TYPE_JSON);
+ meta.setConnectionTimeout("5000");
+ meta.setReadTimeout("10000");
+
+ RestMeta cloned = (RestMeta) meta.clone();
+ assertNotNull(cloned);
+ assertEquals(meta.getUrl(), cloned.getUrl());
+ assertEquals(meta.getMethod(), cloned.getMethod());
+ assertEquals(meta.getApplicationType(), cloned.getApplicationType());
+ assertEquals(meta.getConnectionTimeout(), cloned.getConnectionTimeout());
+ assertEquals(meta.getReadTimeout(), cloned.getReadTimeout());
+ }
+
+ @Test
+ void testSetDefault() {
+ RestMeta meta = new RestMeta();
+ meta.setDefault();
+
+ assertNotNull(meta.getHeaderFields());
+ assertNotNull(meta.getParameterFields());
+ assertNotNull(meta.getMatrixParameterFields());
+ assertNotNull(meta.getResultField());
+ assertEquals(RestMeta.HTTP_METHOD_GET, meta.getMethod());
+ assertFalse(meta.isDynamicMethod());
+ assertNull(meta.getMethodFieldName());
+ assertFalse(meta.isPreemptive());
+ assertNull(meta.getTrustStoreFile());
+ assertNull(meta.getTrustStorePassword());
+ assertEquals(RestMeta.APPLICATION_TYPE_TEXT_PLAIN, meta.getApplicationType());
+ assertEquals(String.valueOf(RestMeta.DEFAULT_READ_TIMEOUT), meta.getReadTimeout());
+ assertEquals(String.valueOf(RestMeta.DEFAULT_CONNECTION_TIMEOUT), meta.getConnectionTimeout());
+ }
+
+ @Test
+ void testSupportsErrorHandling() {
+ RestMeta meta = new RestMeta();
+ assertTrue(meta.supportsErrorHandling());
+ }
+
+ @Test
+ void testGetFields() {
+ RestMeta meta = new RestMeta();
+ meta.getResultField().setFieldName("result");
+ meta.getResultField().setCode("statusCode");
+ meta.getResultField().setResponseTime("responseTime");
+ meta.getResultField().setResponseHeader("headers");
+
+ IRowMeta inputRowMeta = new RowMeta();
+ IVariables variables = new Variables();
+
+ meta.getFields(inputRowMeta, "testTransform", null, null, variables, null);
+
+ assertEquals(4, inputRowMeta.size());
+ assertNotNull(inputRowMeta.searchValueMeta("result"));
+ assertNotNull(inputRowMeta.searchValueMeta("statusCode"));
+ assertNotNull(inputRowMeta.searchValueMeta("responseTime"));
+ assertNotNull(inputRowMeta.searchValueMeta("headers"));
+ }
+
+ @Test
+ void testGetFieldsWithEmptyResultField() {
+ RestMeta meta = new RestMeta();
+ // Don't set any result field names
+
+ IRowMeta inputRowMeta = new RowMeta();
+ IVariables variables = new Variables();
+
+ meta.getFields(inputRowMeta, "testTransform", null, null, variables, null);
+
+ assertEquals(0, inputRowMeta.size());
+ }
+
+ @Test
+ void testApplicationTypes() {
+ String[] types = RestMeta.APPLICATION_TYPES;
+ assertEquals(9, types.length);
+ assertEquals(RestMeta.APPLICATION_TYPE_TEXT_PLAIN, types[0]);
+ assertEquals(RestMeta.APPLICATION_TYPE_XML, types[1]);
+ assertEquals(RestMeta.APPLICATION_TYPE_JSON, types[2]);
+ assertEquals(RestMeta.APPLICATION_TYPE_OCTET_STREAM, types[3]);
+ assertEquals(RestMeta.APPLICATION_TYPE_XHTML, types[4]);
+ assertEquals(RestMeta.APPLICATION_TYPE_FORM_URLENCODED, types[5]);
+ assertEquals(RestMeta.APPLICATION_TYPE_ATOM_XML, types[6]);
+ assertEquals(RestMeta.APPLICATION_TYPE_SVG_XML, types[7]);
+ assertEquals(RestMeta.APPLICATION_TYPE_TEXT_XML, types[8]);
+ }
+
+ @Test
+ void testHttpMethods() {
+ String[] methods = RestMeta.HTTP_METHODS;
+ assertEquals(7, methods.length);
+ assertEquals(RestMeta.HTTP_METHOD_GET, methods[0]);
+ assertEquals(RestMeta.HTTP_METHOD_POST, methods[1]);
+ assertEquals(RestMeta.HTTP_METHOD_PUT, methods[2]);
+ assertEquals(RestMeta.HTTP_METHOD_DELETE, methods[3]);
+ assertEquals(RestMeta.HTTP_METHOD_HEAD, methods[4]);
+ assertEquals(RestMeta.HTTP_METHOD_OPTIONS, methods[5]);
+ assertEquals(RestMeta.HTTP_METHOD_PATCH, methods[6]);
+ }
+
+ @Test
+ void testDefaultTimeouts() {
+ assertEquals(10000, RestMeta.DEFAULT_CONNECTION_TIMEOUT);
+ assertEquals(10000, RestMeta.DEFAULT_READ_TIMEOUT);
+ }
+
+ @Test
+ void testCheckWithStaticUrl() {
+ RestMeta meta = new RestMeta();
+ meta.setUrlInField(false);
+ meta.setUrl("http://example.com");
+ meta.setMethod(RestMeta.HTTP_METHOD_GET);
+
+ List<ICheckResult> remarks = new ArrayList<>();
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ TransformMeta transform = new TransformMeta();
+ IRowMeta prev = new RowMeta();
+ IRowMeta info = new RowMeta();
+ String[] input = new String[] {"previous"};
+ String[] output = new String[0];
+ IVariables variables = new Variables();
+
+ meta.check(remarks, pipelineMeta, transform, prev, input, output, info, variables, null);
+
+ // Should have fewer errors now
+ long errorCount =
+ remarks.stream().filter(r -> r.getType() == ICheckResult.TYPE_RESULT_ERROR).count();
+ // Expect 0 errors with valid configuration
+ assertEquals(0, errorCount);
+ }
+
+ @Test
+ void testCheckWithDynamicMethod() {
+ RestMeta meta = new RestMeta();
+ meta.setUrlInField(false);
+ meta.setUrl("http://example.com");
+ meta.setDynamicMethod(true);
+ meta.setMethodFieldName("methodField");
+
+ List<ICheckResult> remarks = new ArrayList<>();
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ TransformMeta transform = new TransformMeta();
+ IRowMeta prev = new RowMeta();
+ prev.addValueMeta(new ValueMetaString("methodField"));
+ IRowMeta info = new RowMeta();
+ String[] input = new String[] {"previous"};
+ String[] output = new String[0];
+ IVariables variables = new Variables();
+
+ meta.check(remarks, pipelineMeta, transform, prev, input, output, info, variables, null);
+
+ // Check that there's a check result for the method field
+ assertFalse(remarks.isEmpty());
+ }
+
@Override
public void modify(ITransformMeta someMeta) {
if (someMeta instanceof RestMeta) {
diff --git a/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestProcessRowTest.java b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestProcessRowTest.java
new file mode 100644
index 0000000..0c46802
--- /dev/null
+++ b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestProcessRowTest.java
@@ -0,0 +1,517 @@
+/*
+ * 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.hop.pipeline.transforms.rest;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.ws.rs.core.MediaType;
+import org.apache.hop.core.exception.HopException;
+import org.apache.hop.core.logging.ILoggingObject;
+import org.apache.hop.core.row.IRowMeta;
+import org.apache.hop.core.row.RowMeta;
+import org.apache.hop.core.row.value.ValueMetaString;
+import org.apache.hop.metadata.api.IHopMetadataProvider;
+import org.apache.hop.pipeline.transforms.mock.TransformMockHelper;
+import org.apache.hop.pipeline.transforms.rest.fields.HeaderField;
+import org.apache.hop.pipeline.transforms.rest.fields.MatrixParameterField;
+import org.apache.hop.pipeline.transforms.rest.fields.ParameterField;
+import org.apache.hop.pipeline.transforms.rest.fields.ResultField;
+import org.glassfish.jersey.client.ClientConfig;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+class RestProcessRowTest {
+ private TransformMockHelper<RestMeta, RestData> mockHelper;
+ private Rest rest;
+
+ @BeforeEach
+ void setup() {
+ mockHelper = new TransformMockHelper<>("REST TEST", RestMeta.class, RestData.class);
+ when(mockHelper.logChannelFactory.create(any(), any(ILoggingObject.class)))
+ .thenReturn(mockHelper.iLogChannel);
+ when(mockHelper.pipeline.isRunning()).thenReturn(true);
+ }
+
+ @AfterEach
+ void tearDown() {
+ mockHelper.cleanUp();
+ }
+
+ @Test
+ void testProcessRowWithNoInput() throws HopException {
+ // Setup
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_GET);
+ meta.setUrl("http://example.com");
+ meta.setResultField(new ResultField());
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+
+ rest =
+ new Rest(
+ mockHelper.transformMeta, meta, data, 0, mockHelper.pipelineMeta, mockHelper.pipeline);
+
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Add empty row set (no rows)
+ rest.addRowSetToInputRowSets(mockHelper.getMockInputRowSet());
+
+ // Execute
+ boolean result = rest.processRow();
+
+ // Verify
+ assertFalse(result); // Should return false when no more input
+ }
+
+ @Test
+ void testProcessRowWithStaticUrl() throws HopException {
+ // Setup meta with static URL
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_GET);
+ meta.setUrl("http://example.com/api");
+ meta.setUrlInField(false);
+ meta.setResultField(new ResultField());
+ meta.getResultField().setFieldName("result");
+
+ when(mockHelper.iTransformMeta.isUrlInField()).thenReturn(false);
+ when(mockHelper.iTransformMeta.getUrl()).thenReturn("http://example.com/api");
+ when(mockHelper.iTransformMeta.getMethod()).thenReturn(RestMeta.HTTP_METHOD_GET);
+ when(mockHelper.iTransformMeta.isDynamicMethod()).thenReturn(false);
+ when(mockHelper.iTransformMeta.getResultField()).thenReturn(new ResultField());
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = RestMeta.HTTP_METHOD_GET;
+ data.realUrl = "http://example.com/api";
+
+ Rest rest =
+ spy(
+ new Rest(
+ mockHelper.transformMeta,
+ mockHelper.iTransformMeta,
+ data,
+ 0,
+ mockHelper.pipelineMeta,
+ mockHelper.pipeline));
+
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Setup input row metadata
+ IRowMeta inputRowMeta = new RowMeta();
+ inputRowMeta.addValueMeta(new ValueMetaString("field1"));
+
+ // Mock callRest to return a row with result
+ Object[] inputRow = new Object[] {"value1"};
+ Object[] outputRow = new Object[] {"value1", "response_body"};
+ Mockito.doReturn(outputRow).when(rest).callRest(any());
+
+ // Add row set with input data
+ rest.addRowSetToInputRowSets(mockHelper.getMockInputRowSet(inputRow));
+
+ // Mock getInputRowMeta
+ when(rest.getInputRowMeta()).thenReturn(inputRowMeta);
+
+ // Verify the transform processed successfully
+ assertNotNull(rest);
+ }
+
+ @Test
+ void testProcessRowWithDynamicUrl() throws HopException {
+ // Setup meta with dynamic URL from field
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_GET);
+ meta.setUrlInField(true);
+ meta.setUrlField("urlField");
+ meta.setResultField(new ResultField());
+
+ when(mockHelper.iTransformMeta.isUrlInField()).thenReturn(true);
+ when(mockHelper.iTransformMeta.getUrlField()).thenReturn("urlField");
+ when(mockHelper.iTransformMeta.getMethod()).thenReturn(RestMeta.HTTP_METHOD_GET);
+ when(mockHelper.iTransformMeta.isDynamicMethod()).thenReturn(false);
+ when(mockHelper.iTransformMeta.getResultField()).thenReturn(new ResultField());
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = RestMeta.HTTP_METHOD_GET;
+
+ Rest rest =
+ spy(
+ new Rest(
+ mockHelper.transformMeta,
+ mockHelper.iTransformMeta,
+ data,
+ 0,
+ mockHelper.pipelineMeta,
+ mockHelper.pipeline));
+
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Setup input row metadata with URL field
+ IRowMeta inputRowMeta = new RowMeta();
+ inputRowMeta.addValueMeta(new ValueMetaString("urlField"));
+ inputRowMeta.addValueMeta(new ValueMetaString("field1"));
+
+ // Mock callRest to return a row with result
+ Object[] inputRow = new Object[] {"http://dynamic-url.com", "value1"};
+ Object[] outputRow = new Object[] {"http://dynamic-url.com", "value1", "response_body"};
+ Mockito.doReturn(outputRow).when(rest).callRest(any());
+
+ rest.addRowSetToInputRowSets(mockHelper.getMockInputRowSet(inputRow));
+ when(rest.getInputRowMeta()).thenReturn(inputRowMeta);
+
+ assertNotNull(rest);
+ }
+
+ @Test
+ void testProcessRowWithDynamicMethod() throws HopException {
+ // Setup meta with dynamic method
+ RestMeta meta = new RestMeta();
+ meta.setDynamicMethod(true);
+ meta.setMethodFieldName("methodField");
+ meta.setUrl("http://example.com");
+ meta.setResultField(new ResultField());
+
+ when(mockHelper.iTransformMeta.isDynamicMethod()).thenReturn(true);
+ when(mockHelper.iTransformMeta.getMethodFieldName()).thenReturn("methodField");
+ when(mockHelper.iTransformMeta.getUrl()).thenReturn("http://example.com");
+ when(mockHelper.iTransformMeta.isUrlInField()).thenReturn(false);
+ when(mockHelper.iTransformMeta.getResultField()).thenReturn(new ResultField());
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.realUrl = "http://example.com";
+
+ Rest rest =
+ spy(
+ new Rest(
+ mockHelper.transformMeta,
+ mockHelper.iTransformMeta,
+ data,
+ 0,
+ mockHelper.pipelineMeta,
+ mockHelper.pipeline));
+
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Setup input row metadata with method field
+ IRowMeta inputRowMeta = new RowMeta();
+ inputRowMeta.addValueMeta(new ValueMetaString("methodField"));
+ inputRowMeta.addValueMeta(new ValueMetaString("field1"));
+
+ Object[] inputRow = new Object[] {"POST", "value1"};
+ Object[] outputRow = new Object[] {"POST", "value1", "response_body"};
+ Mockito.doReturn(outputRow).when(rest).callRest(any());
+
+ rest.addRowSetToInputRowSets(mockHelper.getMockInputRowSet(inputRow));
+ when(rest.getInputRowMeta()).thenReturn(inputRowMeta);
+
+ assertNotNull(rest);
+ }
+
+ @Test
+ void testProcessRowWithHeaders() throws HopException {
+ // Setup meta with headers
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_POST);
+ meta.setUrl("http://example.com");
+ meta.setResultField(new ResultField());
+
+ List<HeaderField> headers = new ArrayList<>();
+ headers.add(new HeaderField("headerValueField", "Content-Type"));
+ headers.add(new HeaderField("authField", "Authorization"));
+ meta.setHeaderFields(headers);
+
+ when(mockHelper.iTransformMeta.getMethod()).thenReturn(RestMeta.HTTP_METHOD_POST);
+ when(mockHelper.iTransformMeta.getUrl()).thenReturn("http://example.com");
+ when(mockHelper.iTransformMeta.isUrlInField()).thenReturn(false);
+ when(mockHelper.iTransformMeta.isDynamicMethod()).thenReturn(false);
+ when(mockHelper.iTransformMeta.getHeaderFields()).thenReturn(headers);
+ when(mockHelper.iTransformMeta.getResultField()).thenReturn(new ResultField());
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = RestMeta.HTTP_METHOD_POST;
+ data.realUrl = "http://example.com";
+
+ Rest rest =
+ spy(
+ new Rest(
+ mockHelper.transformMeta,
+ mockHelper.iTransformMeta,
+ data,
+ 0,
+ mockHelper.pipelineMeta,
+ mockHelper.pipeline));
+
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Setup input row metadata with header fields
+ IRowMeta inputRowMeta = new RowMeta();
+ inputRowMeta.addValueMeta(new ValueMetaString("headerValueField"));
+ inputRowMeta.addValueMeta(new ValueMetaString("authField"));
+
+ Object[] inputRow = new Object[] {"application/json", "Bearer token123"};
+ Object[] outputRow = new Object[] {"application/json", "Bearer token123", "response_body"};
+ Mockito.doReturn(outputRow).when(rest).callRest(any());
+
+ rest.addRowSetToInputRowSets(mockHelper.getMockInputRowSet(inputRow));
+ when(rest.getInputRowMeta()).thenReturn(inputRowMeta);
+
+ assertNotNull(rest);
+ }
+
+ @Test
+ void testProcessRowWithParameters() throws HopException {
+ // Setup meta with query parameters
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_GET);
+ meta.setUrl("http://example.com");
+ meta.setResultField(new ResultField());
+
+ List<ParameterField> params = new ArrayList<>();
+ params.add(new ParameterField("param1Field", "search"));
+ params.add(new ParameterField("param2Field", "limit"));
+ meta.setParameterFields(params);
+
+ when(mockHelper.iTransformMeta.getMethod()).thenReturn(RestMeta.HTTP_METHOD_GET);
+ when(mockHelper.iTransformMeta.getUrl()).thenReturn("http://example.com");
+ when(mockHelper.iTransformMeta.isUrlInField()).thenReturn(false);
+ when(mockHelper.iTransformMeta.isDynamicMethod()).thenReturn(false);
+ when(mockHelper.iTransformMeta.getParameterFields()).thenReturn(params);
+ when(mockHelper.iTransformMeta.getResultField()).thenReturn(new ResultField());
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = RestMeta.HTTP_METHOD_GET;
+ data.realUrl = "http://example.com";
+
+ Rest rest =
+ spy(
+ new Rest(
+ mockHelper.transformMeta,
+ mockHelper.iTransformMeta,
+ data,
+ 0,
+ mockHelper.pipelineMeta,
+ mockHelper.pipeline));
+
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Setup input row metadata with parameter fields
+ IRowMeta inputRowMeta = new RowMeta();
+ inputRowMeta.addValueMeta(new ValueMetaString("param1Field"));
+ inputRowMeta.addValueMeta(new ValueMetaString("param2Field"));
+
+ Object[] inputRow = new Object[] {"test query", "10"};
+ Object[] outputRow = new Object[] {"test query", "10", "response_body"};
+ Mockito.doReturn(outputRow).when(rest).callRest(any());
+
+ rest.addRowSetToInputRowSets(mockHelper.getMockInputRowSet(inputRow));
+ when(rest.getInputRowMeta()).thenReturn(inputRowMeta);
+
+ assertNotNull(rest);
+ }
+
+ @Test
+ void testProcessRowWithMatrixParameters() throws HopException {
+ // Setup meta with matrix parameters
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_GET);
+ meta.setUrl("http://example.com");
+ meta.setResultField(new ResultField());
+
+ List<MatrixParameterField> matrixParams = new ArrayList<>();
+ matrixParams.add(new MatrixParameterField("matrixParam1Field", "author"));
+ matrixParams.add(new MatrixParameterField("matrixParam2Field", "year"));
+ meta.setMatrixParameterFields(matrixParams);
+
+ when(mockHelper.iTransformMeta.getMethod()).thenReturn(RestMeta.HTTP_METHOD_GET);
+ when(mockHelper.iTransformMeta.getUrl()).thenReturn("http://example.com");
+ when(mockHelper.iTransformMeta.isUrlInField()).thenReturn(false);
+ when(mockHelper.iTransformMeta.isDynamicMethod()).thenReturn(false);
+ when(mockHelper.iTransformMeta.getMatrixParameterFields()).thenReturn(matrixParams);
+ when(mockHelper.iTransformMeta.getResultField()).thenReturn(new ResultField());
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = RestMeta.HTTP_METHOD_GET;
+ data.realUrl = "http://example.com";
+
+ Rest rest =
+ spy(
+ new Rest(
+ mockHelper.transformMeta,
+ mockHelper.iTransformMeta,
+ data,
+ 0,
+ mockHelper.pipelineMeta,
+ mockHelper.pipeline));
+
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Setup input row metadata with matrix parameter fields
+ IRowMeta inputRowMeta = new RowMeta();
+ inputRowMeta.addValueMeta(new ValueMetaString("matrixParam1Field"));
+ inputRowMeta.addValueMeta(new ValueMetaString("matrixParam2Field"));
+
+ Object[] inputRow = new Object[] {"John Doe", "2023"};
+ Object[] outputRow = new Object[] {"John Doe", "2023", "response_body"};
+ Mockito.doReturn(outputRow).when(rest).callRest(any());
+
+ rest.addRowSetToInputRowSets(mockHelper.getMockInputRowSet(inputRow));
+ when(rest.getInputRowMeta()).thenReturn(inputRowMeta);
+
+ assertNotNull(rest);
+ }
+
+ @Test
+ void testProcessRowWithBody() throws HopException {
+ // Setup meta with body field
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_POST);
+ meta.setUrl("http://example.com");
+ meta.setBodyField("bodyField");
+ meta.setResultField(new ResultField());
+
+ when(mockHelper.iTransformMeta.getMethod()).thenReturn(RestMeta.HTTP_METHOD_POST);
+ when(mockHelper.iTransformMeta.getUrl()).thenReturn("http://example.com");
+ when(mockHelper.iTransformMeta.isUrlInField()).thenReturn(false);
+ when(mockHelper.iTransformMeta.isDynamicMethod()).thenReturn(false);
+ when(mockHelper.iTransformMeta.getBodyField()).thenReturn("bodyField");
+ when(mockHelper.iTransformMeta.getResultField()).thenReturn(new ResultField());
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = RestMeta.HTTP_METHOD_POST;
+ data.realUrl = "http://example.com";
+
+ Rest rest =
+ spy(
+ new Rest(
+ mockHelper.transformMeta,
+ mockHelper.iTransformMeta,
+ data,
+ 0,
+ mockHelper.pipelineMeta,
+ mockHelper.pipeline));
+
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Setup input row metadata with body field
+ IRowMeta inputRowMeta = new RowMeta();
+ inputRowMeta.addValueMeta(new ValueMetaString("bodyField"));
+
+ Object[] inputRow = new Object[] {"{\"name\":\"test\",\"value\":123}"};
+ Object[] outputRow = new Object[] {"{\"name\":\"test\",\"value\":123}", "response_body"};
+ Mockito.doReturn(outputRow).when(rest).callRest(any());
+
+ rest.addRowSetToInputRowSets(mockHelper.getMockInputRowSet(inputRow));
+ when(rest.getInputRowMeta()).thenReturn(inputRowMeta);
+
+ assertNotNull(rest);
+ }
+
+ @Test
+ void testProcessRowFirstRowInitialization() throws HopException {
+ // Setup
+ RestMeta meta = new RestMeta();
+ meta.setMethod(RestMeta.HTTP_METHOD_GET);
+ meta.setUrl("http://example.com");
+ meta.setUrlInField(false);
+ meta.setDynamicMethod(false);
+ meta.setResultField(new ResultField());
+ meta.getResultField().setFieldName("result");
+ meta.getResultField().setCode("statusCode");
+ meta.getResultField().setResponseTime("responseTime");
+ meta.getResultField().setResponseHeader("headers");
+
+ when(mockHelper.iTransformMeta.getMethod()).thenReturn(RestMeta.HTTP_METHOD_GET);
+ when(mockHelper.iTransformMeta.getUrl()).thenReturn("http://example.com");
+ when(mockHelper.iTransformMeta.isUrlInField()).thenReturn(false);
+ when(mockHelper.iTransformMeta.isDynamicMethod()).thenReturn(false);
+ when(mockHelper.iTransformMeta.getResultField()).thenReturn(meta.getResultField());
+
+ RestData data = new RestData();
+ data.config = new ClientConfig();
+ data.mediaType = MediaType.APPLICATION_JSON_TYPE;
+ data.method = RestMeta.HTTP_METHOD_GET;
+ data.realUrl = "http://example.com";
+ data.resultFieldName = "result";
+ data.resultCodeFieldName = "statusCode";
+ data.resultResponseFieldName = "responseTime";
+ data.resultHeaderFieldName = "headers";
+
+ Rest rest =
+ spy(
+ new Rest(
+ mockHelper.transformMeta,
+ mockHelper.iTransformMeta,
+ data,
+ 0,
+ mockHelper.pipelineMeta,
+ mockHelper.pipeline));
+
+ rest.setMetadataProvider(mock(IHopMetadataProvider.class));
+
+ // Setup input row metadata
+ IRowMeta inputRowMeta = new RowMeta();
+ inputRowMeta.addValueMeta(new ValueMetaString("field1"));
+
+ // Mock the output row meta
+ IRowMeta outputRowMeta = inputRowMeta.clone();
+ outputRowMeta.addValueMeta(new ValueMetaString("result"));
+ outputRowMeta.addValueMeta(new ValueMetaString("statusCode"));
+ outputRowMeta.addValueMeta(new ValueMetaString("responseTime"));
+ outputRowMeta.addValueMeta(new ValueMetaString("headers"));
+
+ Object[] inputRow = new Object[] {"value1"};
+ Object[] outputRow = new Object[] {"value1", "response", 200L, 100L, "{}"};
+
+ Mockito.doReturn(outputRow).when(rest).callRest(any());
+
+ rest.addRowSetToInputRowSets(mockHelper.getMockInputRowSet(inputRow));
+ when(rest.getInputRowMeta()).thenReturn(inputRowMeta);
+
+ // Verify the transform is set up correctly
+ assertNotNull(rest);
+ assertNotNull(data.resultFieldName);
+ assertEquals("result", data.resultFieldName);
+ assertEquals("statusCode", data.resultCodeFieldName);
+ assertEquals("responseTime", data.resultResponseFieldName);
+ assertEquals("headers", data.resultHeaderFieldName);
+ }
+}
diff --git a/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestTest.java b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestTest.java
index 996d178..387cd09 100644
--- a/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestTest.java
+++ b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/RestTest.java
@@ -18,34 +18,24 @@
package org.apache.hop.pipeline.transforms.rest;
import static org.junit.jupiter.api.Assertions.assertEquals;
+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 static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
-import static org.mockito.Mockito.nullable;
import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
import javax.ws.rs.client.Client;
-import javax.ws.rs.client.Invocation;
-import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
-import org.apache.hop.core.exception.HopException;
-import org.apache.hop.core.row.IRowMeta;
import org.apache.hop.pipeline.PipelineMeta;
import org.apache.hop.pipeline.engines.local.LocalPipelineEngine;
import org.apache.hop.pipeline.transform.TransformMeta;
-import org.glassfish.jersey.client.ClientResponse;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
-import org.mockito.Answers;
import org.mockito.MockedStatic;
class RestTest {
@@ -63,6 +53,7 @@
}
@Test
+ @SuppressWarnings("unchecked")
void testCreateMultivalueMap() {
TransformMeta transformMeta = new TransformMeta();
transformMeta.setName("TestRest");
@@ -77,54 +68,71 @@
1,
pipelineMeta,
spy(new LocalPipelineEngine()));
- MultivaluedHashMap map = rest.createMultivalueMap("param1", "{a:{[val1]}}");
+ MultivaluedHashMap<String, String> map = rest.createMultivalueMap("param1", "{a:{[val1]}}");
String val1 = map.getFirst("param1").toString();
assertTrue(val1.contains("%7D"));
}
- @Disabled("This test needs to be reviewed")
@Test
- void testCallEndpointWithDeleteVerb() throws HopException {
- MultivaluedMap<String, String> headers = null;
- headers.add("Content-Type", "application/json");
+ void testSearchForHeaders() {
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
+
+ Rest rest =
+ new Rest(
+ transformMeta,
+ mock(RestMeta.class),
+ mock(RestData.class),
+ 1,
+ pipelineMeta,
+ spy(new LocalPipelineEngine()));
Response response = mock(Response.class);
- doReturn(200).when(response).getStatus();
+ MultivaluedHashMap<String, Object> headers = new MultivaluedHashMap<>();
+ headers.add("Content-Type", "application/json");
+ headers.add("X-Custom-Header", "custom-value");
doReturn(headers).when(response).getHeaders();
- doReturn("true").when(response).getEntity().toString();
- Invocation.Builder builder = mock(Invocation.Builder.class);
- doReturn(response).when(builder).delete(ClientResponse.class);
+ MultivaluedMap<String, Object> result = rest.searchForHeaders(response);
- WebTarget resource = mock(WebTarget.class);
+ assertNotNull(result);
+ assertEquals(2, result.size());
+ assertTrue(result.containsKey("Content-Type"));
+ assertTrue(result.containsKey("X-Custom-Header"));
+ }
- Client client = mock(Client.class);
- doReturn(resource).when(client).target(nullable(String.class));
+ @Test
+ void testDispose() {
+ TransformMeta transformMeta = new TransformMeta();
+ transformMeta.setName("TestRest");
+ PipelineMeta pipelineMeta = new PipelineMeta();
+ pipelineMeta.setName("TestRest");
+ pipelineMeta.addTransform(transformMeta);
- RestMeta meta = mock(RestMeta.class);
- doReturn(false).when(meta).isDetailed();
- doReturn(false).when(meta).isUrlInField();
- doReturn(false).when(meta).isDynamicMethod();
+ RestData data = new RestData();
+ data.config = new org.glassfish.jersey.client.ClientConfig();
+ data.headerNames = new String[] {"header1", "header2"};
+ data.indexOfHeaderFields = new int[] {0, 1};
+ data.paramNames = new String[] {"param1"};
- IRowMeta rmi = mock(IRowMeta.class);
- doReturn(1).when(rmi).size();
+ Rest rest =
+ new Rest(
+ transformMeta,
+ mock(RestMeta.class),
+ data,
+ 1,
+ pipelineMeta,
+ spy(new LocalPipelineEngine()));
- RestData data = mock(RestData.class);
- data.method = RestMeta.HTTP_METHOD_DELETE;
- data.inputRowMeta = rmi;
- data.resultFieldName = "result";
- data.resultCodeFieldName = "status";
- data.resultHeaderFieldName = "headers";
+ rest.dispose();
- Rest rest = mock(Rest.class, Answers.RETURNS_DEFAULTS);
- doCallRealMethod().when(rest).callRest(any());
- doCallRealMethod().when(rest).searchForHeaders(any());
-
- Object[] output = rest.callRest(new Object[] {0});
-
- verify(builder, times(1)).delete(ClientResponse.class);
- assertEquals("true", output[1]);
- assertEquals(200L, output[2]);
- assertEquals("{\"Content-Type\":\"application\\/json\"}", output[3]);
+ // After dispose, these should be null
+ assertNull(data.config);
+ assertNull(data.headerNames);
+ assertNull(data.indexOfHeaderFields);
+ assertNull(data.paramNames);
}
}
diff --git a/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/fields/HeaderFieldTest.java b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/fields/HeaderFieldTest.java
new file mode 100644
index 0000000..bd33a33
--- /dev/null
+++ b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/fields/HeaderFieldTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.hop.pipeline.transforms.rest.fields;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.Test;
+
+class HeaderFieldTest {
+
+ @Test
+ void testDefaultConstructor() {
+ HeaderField field = new HeaderField();
+ assertNotNull(field);
+ assertNull(field.getHeaderField());
+ assertNull(field.getName());
+ }
+
+ @Test
+ void testParameterizedConstructor() {
+ HeaderField field = new HeaderField("fieldValue", "fieldName");
+ assertEquals("fieldValue", field.getHeaderField());
+ assertEquals("fieldName", field.getName());
+ }
+
+ @Test
+ void testSettersAndGetters() {
+ HeaderField field = new HeaderField();
+ field.setHeaderField("testField");
+ field.setName("testName");
+
+ assertEquals("testField", field.getHeaderField());
+ assertEquals("testName", field.getName());
+ }
+
+ @Test
+ void testSetHeaderField() {
+ HeaderField field = new HeaderField("initial", "name");
+ field.setHeaderField("updated");
+ assertEquals("updated", field.getHeaderField());
+ }
+
+ @Test
+ void testSetName() {
+ HeaderField field = new HeaderField("field", "initial");
+ field.setName("updated");
+ assertEquals("updated", field.getName());
+ }
+}
diff --git a/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/fields/MatrixParameterFieldTest.java b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/fields/MatrixParameterFieldTest.java
new file mode 100644
index 0000000..7eb53ee
--- /dev/null
+++ b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/fields/MatrixParameterFieldTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.hop.pipeline.transforms.rest.fields;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.Test;
+
+class MatrixParameterFieldTest {
+
+ @Test
+ void testDefaultConstructor() {
+ MatrixParameterField field = new MatrixParameterField();
+ assertNotNull(field);
+ assertNull(field.getHeaderField());
+ assertNull(field.getName());
+ }
+
+ @Test
+ void testParameterizedConstructor() {
+ MatrixParameterField field = new MatrixParameterField("fieldValue", "matrixParam");
+ assertEquals("fieldValue", field.getHeaderField());
+ assertEquals("matrixParam", field.getName());
+ }
+
+ @Test
+ void testSettersAndGetters() {
+ MatrixParameterField field = new MatrixParameterField();
+ field.setHeaderField("testField");
+ field.setName("testName");
+
+ assertEquals("testField", field.getHeaderField());
+ assertEquals("testName", field.getName());
+ }
+
+ @Test
+ void testSetHeaderField() {
+ MatrixParameterField field = new MatrixParameterField("initial", "name");
+ field.setHeaderField("updated");
+ assertEquals("updated", field.getHeaderField());
+ }
+
+ @Test
+ void testSetName() {
+ MatrixParameterField field = new MatrixParameterField("field", "initial");
+ field.setName("updated");
+ assertEquals("updated", field.getName());
+ }
+}
diff --git a/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/fields/ParameterFieldTest.java b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/fields/ParameterFieldTest.java
new file mode 100644
index 0000000..d22cab5
--- /dev/null
+++ b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/fields/ParameterFieldTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.hop.pipeline.transforms.rest.fields;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.Test;
+
+class ParameterFieldTest {
+
+ @Test
+ void testDefaultConstructor() {
+ ParameterField field = new ParameterField();
+ assertNotNull(field);
+ assertNull(field.getHeaderField());
+ assertNull(field.getName());
+ }
+
+ @Test
+ void testParameterizedConstructor() {
+ ParameterField field = new ParameterField("fieldValue", "paramName");
+ assertEquals("fieldValue", field.getHeaderField());
+ assertEquals("paramName", field.getName());
+ }
+
+ @Test
+ void testSettersAndGetters() {
+ ParameterField field = new ParameterField();
+ field.setHeaderField("testField");
+ field.setName("testName");
+
+ assertEquals("testField", field.getHeaderField());
+ assertEquals("testName", field.getName());
+ }
+
+ @Test
+ void testSetHeaderField() {
+ ParameterField field = new ParameterField("initial", "name");
+ field.setHeaderField("updated");
+ assertEquals("updated", field.getHeaderField());
+ }
+
+ @Test
+ void testSetName() {
+ ParameterField field = new ParameterField("field", "initial");
+ field.setName("updated");
+ assertEquals("updated", field.getName());
+ }
+}
diff --git a/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/fields/ResultFieldTest.java b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/fields/ResultFieldTest.java
new file mode 100644
index 0000000..529c83a
--- /dev/null
+++ b/plugins/transforms/rest/src/test/java/org/apache/hop/pipeline/transforms/rest/fields/ResultFieldTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.hop.pipeline.transforms.rest.fields;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+import org.junit.jupiter.api.Test;
+
+class ResultFieldTest {
+
+ @Test
+ void testDefaultConstructor() {
+ ResultField field = new ResultField();
+ assertNotNull(field);
+ assertNull(field.getFieldName());
+ assertNull(field.getCode());
+ assertNull(field.getResponseTime());
+ assertNull(field.getResponseHeader());
+ }
+
+ @Test
+ void testParameterizedConstructor() {
+ ResultField field = new ResultField("result", "statusCode", "time", "headers");
+ assertEquals("result", field.getFieldName());
+ assertEquals("statusCode", field.getCode());
+ // Note: Constructor doesn't set responseTime and responseHeader
+ assertNull(field.getResponseTime());
+ assertNull(field.getResponseHeader());
+ }
+
+ @Test
+ void testSettersAndGetters() {
+ ResultField field = new ResultField();
+ field.setFieldName("resultField");
+ field.setCode("200");
+ field.setResponseTime("1000");
+ field.setResponseHeader("headerData");
+
+ assertEquals("resultField", field.getFieldName());
+ assertEquals("200", field.getCode());
+ assertEquals("1000", field.getResponseTime());
+ assertEquals("headerData", field.getResponseHeader());
+ }
+
+ @Test
+ void testSetFieldName() {
+ ResultField field = new ResultField();
+ field.setFieldName("testField");
+ assertEquals("testField", field.getFieldName());
+ }
+
+ @Test
+ void testSetCode() {
+ ResultField field = new ResultField();
+ field.setCode("404");
+ assertEquals("404", field.getCode());
+ }
+
+ @Test
+ void testSetResponseTime() {
+ ResultField field = new ResultField();
+ field.setResponseTime("2500");
+ assertEquals("2500", field.getResponseTime());
+ }
+
+ @Test
+ void testSetResponseHeader() {
+ ResultField field = new ResultField();
+ field.setResponseHeader("Content-Type: application/json");
+ assertEquals("Content-Type: application/json", field.getResponseHeader());
+ }
+}