From 2a7fa6d17b1807091659197c702a221825a30eeb Mon Sep 17 00:00:00 2001 From: dan-s1 Date: Mon, 26 Jun 2023 22:27:51 +0000 Subject: [PATCH] NIFI-11754 Refactored Groovy test in nifi-jetty to Java (and JUnit 5) This closes #7442 Signed-off-by: David Handermann --- .../nifi-web/nifi-jetty/pom.xml | 4 - .../web/server/HostHeaderHandlerTest.groovy | 277 ------------------ .../web/server/HostHeaderHandlerTest.java | 161 ++++++++++ 3 files changed, 161 insertions(+), 281 deletions(-) delete mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/HostHeaderHandlerTest.groovy create mode 100644 nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/HostHeaderHandlerTest.java diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/pom.xml index 0a6d523d5e..48a78383a3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/pom.xml +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/pom.xml @@ -223,10 +223,6 @@ spring-test test - - org.codehaus.groovy - groovy-test - diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/HostHeaderHandlerTest.groovy b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/HostHeaderHandlerTest.groovy deleted file mode 100644 index ae74084f24..0000000000 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/HostHeaderHandlerTest.groovy +++ /dev/null @@ -1,277 +0,0 @@ -/* - * 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.nifi.web.server - -import org.apache.commons.lang3.StringUtils - -import org.apache.nifi.util.NiFiProperties -import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.Test -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -import static org.junit.jupiter.api.Assertions.assertEquals -import static org.junit.jupiter.api.Assertions.assertTrue - -class HostHeaderHandlerTest { - private static final Logger logger = LoggerFactory.getLogger(HostHeaderHandlerTest.class) - - private static final String DEFAULT_HOSTNAME = "nifi.apache.org" - private static final String ACTUAL_HOSTNAME = InetAddress.getLocalHost().getHostName().toLowerCase() - private static final int DEFAULT_PORT = 8080 - private static final List DEFAULT_HOSTS_1_5_0 = [DEFAULT_HOSTNAME, "localhost", ACTUAL_HOSTNAME] - private static - final List DEFAULT_HOSTS_AND_PORTS_1_5_0 = DEFAULT_HOSTS_1_5_0.collectMany { it -> [it, "${it}:${DEFAULT_PORT}"] } - - // Post 1.5.0 list - private static final String ACTUAL_IP = InetAddress.getLocalHost().getHostAddress() - private static final String LOOPBACK_IP = InetAddress.getLoopbackAddress().getHostAddress() - private static - final List DEFAULT_HOSTS = DEFAULT_HOSTS_1_5_0 - DEFAULT_HOSTNAME + ["[::1]", "127.0.0.1", ACTUAL_IP, LOOPBACK_IP] - private static - final List DEFAULT_HOSTS_AND_PORTS = DEFAULT_HOSTS.collectMany { it -> [it, "${it}:${DEFAULT_PORT}"] } - - @BeforeAll - static void setUpOnce() throws Exception { - logger.metaClass.methodMissing = { String name, args -> - logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}") - } - } - - @Test - void testConstructorShouldAcceptSingleValues() throws Exception { - // Arrange - String hostname = DEFAULT_HOSTNAME - int port = DEFAULT_PORT - logger.info("Hostname: ${hostname} | port: ${port}") - - // Act - HostHeaderHandler handler = new HostHeaderHandler(hostname, port) - logger.info("Handler: ${handler}") - - // Assert - assertTrue(handler.hostHeaderIsValid(hostname)) - assertTrue(handler.hostHeaderIsValid("${hostname}:${port}")) - } - - /** - * The feature was introduced in Apache NiFi 1.5.0 but the behavior was changed following that release to include the actual IP address of the server, IPv6 ::1, and 127.0.0.1. - * @throws Exception - */ - @Test - void testShouldHandle_1_5_0_DefaultValues() throws Exception { - // Arrange - String hostname = DEFAULT_HOSTNAME - int port = DEFAULT_PORT - logger.info("Hostname: ${hostname} | port: ${port}") - - // Act - HostHeaderHandler handler = new HostHeaderHandler(hostname, port) - logger.info("Handler: ${handler}") - - // Assert - DEFAULT_HOSTS_AND_PORTS_1_5_0.each { String host -> - logger.debug("Validating ${host}") - assertTrue(handler.hostHeaderIsValid(host)) - } - } - - @Test - void testNewConstructorShouldHandleCurrentDefaultValues() throws Exception { - // Arrange - String hostname = DEFAULT_HOSTNAME - int port = DEFAULT_PORT - logger.info("Hostname: ${hostname} | port: ${port}") - - Properties rawProps = new Properties() - rawProps.putAll([ - (NiFiProperties.WEB_HTTPS_HOST): DEFAULT_HOSTNAME, - (NiFiProperties.WEB_HTTPS_PORT): "${DEFAULT_PORT}".toString(), - ]) - NiFiProperties simpleProperties = new NiFiProperties(rawProps) - - // Act - HostHeaderHandler handler = new HostHeaderHandler(simpleProperties) - logger.info("Handler: ${handler}") - - // Assert - DEFAULT_HOSTS_AND_PORTS.each { String host -> - logger.debug("Validating ${host}") - assertTrue(handler.hostHeaderIsValid(host)) - } - } - - @Test - void testShouldParseCustomHostnames() throws Exception { - // Arrange - String hostname = DEFAULT_HOSTNAME - int port = DEFAULT_PORT - logger.info("Hostname: ${hostname} | port: ${port}") - - List otherHosts = ["someotherhost.com:9999", "yetanotherbadhost.com", "10.10.10.1:1234", "100.100.100.1"] - String concatenatedHosts = otherHosts.join(",") - - Properties rawProps = new Properties() - rawProps.putAll([ - (NiFiProperties.WEB_HTTPS_HOST): DEFAULT_HOSTNAME, - (NiFiProperties.WEB_HTTPS_PORT): "${DEFAULT_PORT}".toString(), - (NiFiProperties.WEB_PROXY_HOST): concatenatedHosts - ]) - NiFiProperties simpleProperties = new NiFiProperties(rawProps) - - HostHeaderHandler handler = new HostHeaderHandler(simpleProperties) - logger.info("Handler: ${handler}") - - // Act - List customHostnames = handler.parseCustomHostnames(simpleProperties) - logger.info("Parsed custom hostnames: ${customHostnames}") - - // Assert - assertEquals(otherHosts.size() + 2, customHostnames.size()) // Two provided hostnames had ports - otherHosts.each { String host -> - logger.debug("Checking ${host}") - assertTrue(customHostnames.contains(host)) - String portlessHost = "${host.split(":", 2)[0]}".toString() - logger.debug("Checking ${portlessHost}") - assertTrue(customHostnames.contains(portlessHost)) - } - } - - @Test - void testParseCustomHostnamesShouldHandleIPv6WithoutPorts() throws Exception { - // Arrange - String hostname = DEFAULT_HOSTNAME - int port = DEFAULT_PORT - logger.info("Hostname: ${hostname} | port: ${port}") - - List ipv6Hosts = ["ABCD:EF01:2345:6789:ABCD:EF01:2345:6789", - "2001:DB8:0:0:8:800:200C:417A", - "FF01:0:0:0:0:0:0:101", - "0:0:0:0:0:0:0:1", - "0:0:0:0:0:0:0:0", - "2001:DB8::8:800:200C:417A", - "FF01::101", - "::1", - "::", - "0:0:0:0:0:0:13.1.68.3", - "0:0:0:0:0:FFFF:129.144.52.38", - "::13.1.68.3", - "FFFF:129.144.52.38", - "::FFFF:129.144.52.38"] - String concatenatedHosts = ipv6Hosts.join(",") - - Properties rawProps = new Properties() - rawProps.putAll([ - (NiFiProperties.WEB_HTTPS_HOST): DEFAULT_HOSTNAME, - (NiFiProperties.WEB_HTTPS_PORT): "${DEFAULT_PORT}".toString(), - (NiFiProperties.WEB_PROXY_HOST): concatenatedHosts - ]) - NiFiProperties simpleProperties = new NiFiProperties(rawProps) - - HostHeaderHandler handler = new HostHeaderHandler(simpleProperties) - logger.info("Handler: ${handler}") - - // Act - List customHostnames = handler.parseCustomHostnames(simpleProperties) - logger.info("Parsed custom hostnames: ${customHostnames}") - - // Assert - assertEquals(ipv6Hosts.size(), customHostnames.size()) - ipv6Hosts.each { String host -> - logger.debug("Checking ${host}") - assertTrue(customHostnames.contains(host)) - } - } - - @Test - void testParseCustomHostnamesShouldHandleIPv6WithPorts() throws Exception { - // Arrange - String hostname = DEFAULT_HOSTNAME - int port = DEFAULT_PORT - logger.info("Hostname: ${hostname} | port: ${port}") - - List ipv6Hosts = ["[ABCD:EF01:2345:6789:ABCD:EF01:2345:6789]:1234", - "[2001:DB8:0:0:8:800:200C:417A]:1234", - "[FF01:0:0:0:0:0:0:101]:1234", - "[0:0:0:0:0:0:0:1]:1234", - "[0:0:0:0:0:0:0:0]:1234", - "[2001:DB8::8:800:200C:417A]:1234", - "[FF01::101]:1234", - "[::1]:1234", - "[::]:1234", - "[0:0:0:0:0:0:13.1.68.3]:1234", - "[0:0:0:0:0:FFFF:129.144.52.38]:1234", - "[::13.1.68.3]:1234", - "[FFFF:129.144.52.38]:1234", - "[::FFFF:129.144.52.38]:1234"] - String concatenatedHosts = ipv6Hosts.join(",") - - Properties rawProps = new Properties() - rawProps.putAll([ - (NiFiProperties.WEB_HTTPS_HOST): DEFAULT_HOSTNAME, - (NiFiProperties.WEB_HTTPS_PORT): "${DEFAULT_PORT}".toString(), - (NiFiProperties.WEB_PROXY_HOST): concatenatedHosts - ]) - NiFiProperties simpleProperties = new NiFiProperties(rawProps) - - HostHeaderHandler handler = new HostHeaderHandler(simpleProperties) - logger.info("Handler: ${handler}") - - // Act - List customHostnames = handler.parseCustomHostnames(simpleProperties) - logger.info("Parsed custom hostnames: ${customHostnames}") - - // Assert - assertEquals(ipv6Hosts.size() * 2, customHostnames.size()) - ipv6Hosts.each { String host -> - logger.debug("Checking ${host}") - assertTrue(customHostnames.contains(host)) - String portlessHost = "${StringUtils.substringBeforeLast(host, ":")}".toString() - logger.debug("Checking ${portlessHost}") - assertTrue(customHostnames.contains(portlessHost)) - } - } - - @Test - void testShouldIdentifyIPv6Addresses() throws Exception { - // Arrange - List ipv6Hosts = ["ABCD:EF01:2345:6789:ABCD:EF01:2345:6789", - "2001:DB8:0:0:8:800:200C:417A", - "FF01:0:0:0:0:0:0:101", - "0:0:0:0:0:0:0:1", - "0:0:0:0:0:0:0:0", - "2001:DB8::8:800:200C:417A", - "FF01::101", - "::1", - "::", - "0:0:0:0:0:0:13.1.68.3", - "0:0:0:0:0:FFFF:129.144.52.38", - "::13.1.68.3", - "FFFF:129.144.52.38", - "::FFFF:129.144.52.38"] - - // Act - List hostsAreIPv6 = ipv6Hosts.collect { String host -> - boolean isIPv6 = HostHeaderHandler.isIPv6Address(host) - logger.info("Hostname is IPv6: ${host} | ${isIPv6}") - isIPv6 - } - - // Assert - hostsAreIPv6.forEach(hostIsIPv6 -> assertTrue(hostIsIPv6)) - } -} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/HostHeaderHandlerTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/HostHeaderHandlerTest.java new file mode 100644 index 0000000000..579ad4c2e3 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-jetty/src/test/java/org/apache/nifi/web/server/HostHeaderHandlerTest.java @@ -0,0 +1,161 @@ +/* + * 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.nifi.web.server; + +import org.apache.commons.lang3.StringUtils; +import org.apache.nifi.util.NiFiProperties; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class HostHeaderHandlerTest { + private static final String DEFAULT_HOSTNAME = "nifi.apache.org"; + private static final int DEFAULT_PORT = 8080; + private static final List IPV6_HOSTS = Arrays.asList("ABCD:EF01:2345:6789:ABCD:EF01:2345:6789", + "2001:DB8:0:0:8:800:200C:417A", + "FF01:0:0:0:0:0:0:101", + "0:0:0:0:0:0:0:1", + "0:0:0:0:0:0:0:0", + "2001:DB8::8:800:200C:417A", + "FF01::101", + "::1", + "::", + "0:0:0:0:0:0:13.1.68.3", + "0:0:0:0:0:FFFF:129.144.52.38", + "::13.1.68.3", + "FFFF:129.144.52.38", + "::FFFF:129.144.52.38"); + + private static List defaultHostsAndPorts150; + private static List defaultHostsAndPorts; + + @BeforeAll + public static void setUpOnce() throws Exception { + String actualHostname = InetAddress.getLocalHost().getHostName().toLowerCase(); + List defaultHosts150 = Arrays.asList(DEFAULT_HOSTNAME, "localhost", actualHostname); + defaultHostsAndPorts150 = buildHostsWithPorts(defaultHosts150, DEFAULT_PORT); + String actualIp = InetAddress.getLocalHost().getHostAddress(); + String loopbackIp = InetAddress.getLoopbackAddress().getHostAddress(); + List defaultHosts = new ArrayList<>(defaultHosts150); + defaultHosts.remove(DEFAULT_HOSTNAME); + defaultHosts.addAll(Arrays.asList("[::1]", "127.0.0.1", actualIp, loopbackIp)); + defaultHostsAndPorts = buildHostsWithPorts(defaultHosts, DEFAULT_PORT); + } + + @SuppressWarnings("deprecation") + @Test + public void testConstructorShouldAcceptSingleValues() { + HostHeaderHandler handler = new HostHeaderHandler(DEFAULT_HOSTNAME, DEFAULT_PORT); + + assertTrue(handler.hostHeaderIsValid(DEFAULT_HOSTNAME)); + assertTrue(handler.hostHeaderIsValid(DEFAULT_HOSTNAME + ":" + DEFAULT_PORT)); + } + + /** + * The feature was introduced in Apache NiFi 1.5.0 but the behavior was changed following that release to include the actual IP address of the server, IPv6 ::1, and 127.0.0.1. + */ + @SuppressWarnings("deprecation") + @Test + public void testShouldHandle_1_5_0_DefaultValues() { + HostHeaderHandler handler = new HostHeaderHandler(DEFAULT_HOSTNAME, DEFAULT_PORT); + + defaultHostsAndPorts150.forEach(host -> assertTrue(handler.hostHeaderIsValid(host))); + } + + @Test + public void testNewConstructorShouldHandleCurrentDefaultValues() { + HostHeaderHandler handler = new HostHeaderHandler(getNifiProperties(null)); + + defaultHostsAndPorts.forEach(host -> assertTrue(handler.hostHeaderIsValid(host))); + } + + @Test + public void testShouldParseCustomHostnames() { + List otherHosts = Arrays.asList("someotherhost.com:9999", "yetanotherbadhost.com", "10.10.10.1:1234", "100.100.100.1"); + NiFiProperties nifiProperties = getNifiProperties(otherHosts); + HostHeaderHandler handler = new HostHeaderHandler(nifiProperties); + final List customHostnames = handler.parseCustomHostnames(nifiProperties); + + assertEquals(otherHosts.size() + 2, customHostnames.size()); // Two provided hostnames had ports + otherHosts.forEach(host -> { + assertTrue(customHostnames.contains(host)); + String portlessHost = host.split(":", 2)[0]; + assertTrue(customHostnames.contains(portlessHost)); + }); + } + + @Test + public void testParseCustomHostnamesShouldHandleIPv6WithoutPorts() { + NiFiProperties nifiProperties = getNifiProperties(IPV6_HOSTS); + HostHeaderHandler handler = new HostHeaderHandler(nifiProperties); + List customHostnames = handler.parseCustomHostnames(nifiProperties); + + assertEquals(IPV6_HOSTS.size(), customHostnames.size()); + IPV6_HOSTS.forEach(host -> assertTrue(customHostnames.contains(host))); + } + + @Test + public void testParseCustomHostnamesShouldHandleIPv6WithPorts() { + int port = 1234; + List ipv6HostsWithPorts = buildHostsWithPorts(IPV6_HOSTS.stream() + .map(host -> "[" + host + "]") + .collect(Collectors.toList()), port); + NiFiProperties nifiProperties = getNifiProperties(ipv6HostsWithPorts); + HostHeaderHandler handler = new HostHeaderHandler(nifiProperties); + List customHostnames = handler.parseCustomHostnames(nifiProperties); + + assertEquals(ipv6HostsWithPorts.size() * 2, customHostnames.size()); + ipv6HostsWithPorts.forEach(host -> { + assertTrue(customHostnames.contains(host)); + String portlessHost = StringUtils.substringBeforeLast(host, ":"); + assertTrue(customHostnames.contains(portlessHost)); + } + ); + } + + @Test + public void testShouldIdentifyIPv6Addresses() { + IPV6_HOSTS.forEach(host -> assertTrue(HostHeaderHandler.isIPv6Address(host))); + } + + private static List buildHostsWithPorts(List hosts, int port) { + return hosts.stream() + .map(host -> host + ":" + port) + .collect(Collectors.toList()); + } + + private NiFiProperties getNifiProperties(List hosts) { + Properties bareboneProperties = new Properties(); + bareboneProperties.put(NiFiProperties.WEB_HTTPS_HOST, DEFAULT_HOSTNAME); + bareboneProperties.put(NiFiProperties.WEB_HTTPS_PORT, Integer.toString(DEFAULT_PORT)); + + if(hosts != null) { + bareboneProperties.put(NiFiProperties.WEB_PROXY_HOST, String.join(",", hosts)); + } + + return new NiFiProperties(bareboneProperties); + } +}