This is an automated email from the ASF dual-hosted git repository.
exceptionfactory pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new 5cc857b99c NIFI-12017 Added Line Length Properties to EncodeContent
5cc857b99c is described below
commit 5cc857b99c780afb0a28112a73d73ae130b7b1fa
Author: knguyen <[email protected]>
AuthorDate: Thu Feb 15 19:35:13 2024 +0000
NIFI-12017 Added Line Length Properties to EncodeContent
This closes #8417
Signed-off-by: David Handermann <[email protected]>
---
.../nifi/processors/standard/EncodeContent.java | 148 ++++++---
.../processors/standard/encoding/EncodingMode.java | 47 +++
.../processors/standard/encoding/EncodingType.java | 50 +++
.../standard/encoding/LineOutputMode.java | 47 +++
.../processors/standard/TestEncodeContent.java | 348 ++++++++++++++++-----
5 files changed, 520 insertions(+), 120 deletions(-)
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncodeContent.java
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncodeContent.java
index d6e49725b9..29f23ee3ed 100644
---
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncodeContent.java
+++
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EncodeContent.java
@@ -16,6 +16,14 @@
*/
package org.apache.nifi.processors.standard;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base32InputStream;
import org.apache.commons.codec.binary.Base32OutputStream;
@@ -29,25 +37,22 @@ import org.apache.nifi.annotation.behavior.SupportsBatching;
import org.apache.nifi.annotation.documentation.CapabilityDescription;
import org.apache.nifi.annotation.documentation.Tags;
import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.expression.ExpressionLanguageScope;
import org.apache.nifi.flowfile.FlowFile;
import org.apache.nifi.processor.AbstractProcessor;
import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.ProcessSession;
import org.apache.nifi.processor.Relationship;
import org.apache.nifi.processor.io.StreamCallback;
+import org.apache.nifi.processor.util.StandardValidators;
+import org.apache.nifi.processors.standard.encoding.EncodingMode;
+import org.apache.nifi.processors.standard.encoding.EncodingType;
+import org.apache.nifi.processors.standard.encoding.LineOutputMode;
import org.apache.nifi.processors.standard.util.ValidatingBase32InputStream;
import org.apache.nifi.processors.standard.util.ValidatingBase64InputStream;
import org.apache.nifi.stream.io.StreamUtils;
import org.apache.nifi.util.StopWatch;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-
@SideEffectFree
@SupportsBatching
@InputRequirement(Requirement.INPUT_REQUIRED)
@@ -55,33 +60,52 @@ import java.util.concurrent.TimeUnit;
@CapabilityDescription("Encode or decode the contents of a FlowFile using
Base64, Base32, or hex encoding schemes")
public class EncodeContent extends AbstractProcessor {
- public static final String ENCODE_MODE = "Encode";
- public static final String DECODE_MODE = "Decode";
-
- public static final String BASE64_ENCODING = "base64";
- public static final String BASE32_ENCODING = "base32";
- public static final String HEX_ENCODING = "hex";
-
public static final PropertyDescriptor MODE = new
PropertyDescriptor.Builder()
.name("Mode")
- .description("Specifies whether the content should be encoded or
decoded")
+ .description("Specifies whether the content should be encoded or
decoded.")
.required(true)
- .allowableValues(ENCODE_MODE, DECODE_MODE)
- .defaultValue(ENCODE_MODE)
+ .allowableValues(EncodingMode.class)
+ .defaultValue(EncodingMode.ENCODE)
.build();
public static final PropertyDescriptor ENCODING = new
PropertyDescriptor.Builder()
.name("Encoding")
- .description("Specifies the type of encoding used")
+ .description("Specifies the type of encoding used.")
+ .required(true)
+ .allowableValues(EncodingType.class)
+ .defaultValue(EncodingType.BASE64)
+ .build();
+
+ public static final PropertyDescriptor LINE_OUTPUT_MODE = new
PropertyDescriptor.Builder()
+ .name("Line Output Mode")
+ .displayName("Line Output Mode")
+ .description("Controls the line formatting for encoded content
based on selected property values.")
.required(true)
- .allowableValues(BASE64_ENCODING, BASE32_ENCODING, HEX_ENCODING)
- .defaultValue(BASE64_ENCODING)
+ .defaultValue(LineOutputMode.SINGLE_LINE)
+ .allowableValues(LineOutputMode.class)
+ .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+ .dependsOn(MODE, EncodingMode.ENCODE)
+ .dependsOn(ENCODING, EncodingType.BASE64, EncodingType.BASE32)
+ .build();
+
+ public static final PropertyDescriptor ENCODED_LINE_LENGTH = new
PropertyDescriptor.Builder()
+ .name("Encoded Line Length")
+ .displayName("Encoded Line Length")
+ .description("Each line of encoded data will contain up to the
configured number of characters, rounded down to the nearest multiple of 4.")
+ .required(true)
+ .defaultValue("76")
+
.expressionLanguageSupported(ExpressionLanguageScope.FLOWFILE_ATTRIBUTES)
+ .addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR)
+ .dependsOn(MODE, EncodingMode.ENCODE)
+ .dependsOn(ENCODING, EncodingType.BASE64, EncodingType.BASE32)
+ .dependsOn(LINE_OUTPUT_MODE, LineOutputMode.MULTIPLE_LINES)
.build();
public static final Relationship REL_SUCCESS = new Relationship.Builder()
.name("success")
.description("Any FlowFile that is successfully encoded or decoded
will be routed to success")
.build();
+
public static final Relationship REL_FAILURE = new Relationship.Builder()
.name("failure")
.description("Any FlowFile that cannot be encoded or decoded will
be routed to failure")
@@ -89,11 +113,16 @@ public class EncodeContent extends AbstractProcessor {
private static final int BUFFER_SIZE = 8192;
- private static final List<PropertyDescriptor> properties = List.of(MODE,
- ENCODING);
+ private static final String LINE_FEED_SEPARATOR = "\n";
+
+ private static final List<PropertyDescriptor> properties = List.of(
+ MODE,
+ ENCODING,
+ LINE_OUTPUT_MODE,
+ ENCODED_LINE_LENGTH
+ );
- private static final Set<Relationship> relationships = Set.of(REL_SUCCESS,
- REL_FAILURE);
+ private static final Set<Relationship> relationships = Set.of(REL_SUCCESS,
REL_FAILURE);
@Override
public Set<Relationship> getRelationships() {
@@ -112,9 +141,12 @@ public class EncodeContent extends AbstractProcessor {
return;
}
- final boolean encode =
context.getProperty(MODE).getValue().equalsIgnoreCase(ENCODE_MODE);
- final String encoding = context.getProperty(ENCODING).getValue();
- final StreamCallback callback = getStreamCallback(encode, encoding);
+ final boolean encode =
context.getProperty(MODE).getValue().equals(EncodingMode.ENCODE.getValue());
+ final EncodingType encoding =
getEncodingType(context.getProperty(ENCODING).getValue());
+ final boolean singleLineOutput =
context.getProperty(LINE_OUTPUT_MODE).getValue().equals(LineOutputMode.SINGLE_LINE.getValue());
+ final int lineLength = singleLineOutput ? -1 :
context.getProperty(ENCODED_LINE_LENGTH).evaluateAttributeExpressions(flowFile).asInteger();
+
+ final StreamCallback callback = getStreamCallback(encode, encoding,
lineLength);
try {
final StopWatch stopWatch = new StopWatch(true);
@@ -129,31 +161,31 @@ public class EncodeContent extends AbstractProcessor {
}
}
- private static StreamCallback getStreamCallback(final boolean encode,
final String encoding) {
- if (encode) {
- if (encoding.equalsIgnoreCase(BASE64_ENCODING)) {
- return new EncodeBase64();
- } else if (encoding.equalsIgnoreCase(BASE32_ENCODING)) {
- return new EncodeBase32();
- } else {
- return new EncodeHex();
- }
- } else {
- if (encoding.equalsIgnoreCase(BASE64_ENCODING)) {
- return new DecodeBase64();
- } else if (encoding.equalsIgnoreCase(BASE32_ENCODING)) {
- return new DecodeBase32();
- } else {
- return new DecodeHex();
- }
- }
+ private static StreamCallback getStreamCallback(final boolean encode,
final EncodingType encoding, final int lineLength) {
+ return switch (encoding) {
+ case BASE64 -> encode ? new EncodeBase64(lineLength,
LINE_FEED_SEPARATOR) : new DecodeBase64();
+ case BASE32 -> encode ? new EncodeBase32(lineLength,
LINE_FEED_SEPARATOR) : new DecodeBase32();
+ default -> encode ? new EncodeHex() : new DecodeHex();
+ };
}
private static class EncodeBase64 implements StreamCallback {
+ private final int lineLength;
+ private final String lineSeparator;
+
+ private EncodeBase64(final int lineLength,
+ final String lineSeparator) {
+ this.lineLength = lineLength;
+ this.lineSeparator = lineSeparator;
+ }
+
@Override
public void process(final InputStream in, final OutputStream out)
throws IOException {
- try (Base64OutputStream bos = new Base64OutputStream(out)) {
+ try (Base64OutputStream bos = new Base64OutputStream(out,
+ true,
+ this.lineLength,
+ this.lineSeparator.getBytes())) {
StreamUtils.copy(in, bos);
}
}
@@ -171,9 +203,19 @@ public class EncodeContent extends AbstractProcessor {
private static class EncodeBase32 implements StreamCallback {
+ private final int lineLength;
+ private final String lineSeparator;
+
+ public EncodeBase32(final int lineLength,
+ final String lineSeparator) {
+
+ this.lineLength = lineLength;
+ this.lineSeparator = lineSeparator;
+ }
+
@Override
public void process(final InputStream in, final OutputStream out)
throws IOException {
- try (Base32OutputStream bos = new Base32OutputStream(out)) {
+ try (Base32OutputStream bos = new Base32OutputStream(out, true,
this.lineLength, this.lineSeparator.getBytes())) {
StreamUtils.copy(in, bos);
}
}
@@ -237,4 +279,14 @@ public class EncodeContent extends AbstractProcessor {
out.flush();
}
}
+
+ private static EncodingType getEncodingType(final String
encodingTypeValue) {
+ if (EncodingType.BASE64.getValue().equals(encodingTypeValue)) {
+ return EncodingType.BASE64;
+ } else if (EncodingType.BASE32.getValue().equals(encodingTypeValue)) {
+ return EncodingType.BASE32;
+ } else {
+ return EncodingType.HEXADECIMAL;
+ }
+ }
}
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/encoding/EncodingMode.java
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/encoding/EncodingMode.java
new file mode 100644
index 0000000000..710c5ac1b7
--- /dev/null
+++
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/encoding/EncodingMode.java
@@ -0,0 +1,47 @@
+/*
+ * 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.processors.standard.encoding;
+
+import org.apache.nifi.components.DescribedValue;
+
+public enum EncodingMode implements DescribedValue {
+ ENCODE("Encode", "Transform original input to encoded representation"),
+ DECODE("Decode", "Transform encoded input to original representation");
+
+ EncodingMode(String value, String description) {
+ this.value = value;
+ this.description = description;
+ }
+
+ private final String value;
+ private final String description;
+
+ @Override
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public String getDisplayName() {
+ return value;
+ }
+
+ @Override
+ public String getDescription() {
+ return description;
+ }
+ }
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/encoding/EncodingType.java
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/encoding/EncodingType.java
new file mode 100644
index 0000000000..aea183a4d2
--- /dev/null
+++
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/encoding/EncodingType.java
@@ -0,0 +1,50 @@
+/*
+ * 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.processors.standard.encoding;
+
+import org.apache.nifi.components.DescribedValue;
+
+public enum EncodingType implements DescribedValue {
+ BASE64("base64", "Base64", "Encode or decode using Base64 set of
characters"),
+ BASE32("base32", "Base32", "Encode or decode using Base32 set of
characters"),
+ HEXADECIMAL("hex", "Hexadecimal", "Encode or decode using hexadecimal set
of characters");
+
+ private final String value;
+ private final String displayName;
+ private final String description;
+
+ EncodingType(String value, String displayName, String description) {
+ this.value = value;
+ this.displayName = displayName;
+ this.description = description;
+ }
+
+ @Override
+ public String getValue() {
+ return value;
+ }
+
+ @Override
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ @Override
+ public String getDescription() {
+ return description;
+ }
+}
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/encoding/LineOutputMode.java
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/encoding/LineOutputMode.java
new file mode 100644
index 0000000000..71062cf519
--- /dev/null
+++
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/encoding/LineOutputMode.java
@@ -0,0 +1,47 @@
+/*
+ * 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.processors.standard.encoding;
+
+import org.apache.nifi.components.DescribedValue;
+
+public enum LineOutputMode implements DescribedValue {
+ SINGLE_LINE("Single Line", "The encoded content will be written as a
single line."),
+ MULTIPLE_LINES("Multiple Lines", "The encoded content will be written as
multiple lines.");
+
+ private final String displayName;
+ private final String description;
+
+ LineOutputMode(String displayName, String description) {
+ this.displayName = displayName;
+ this.description = description;
+ }
+
+ @Override
+ public String getValue() {
+ return name();
+ }
+
+ @Override
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ @Override
+ public String getDescription() {
+ return description;
+ }
+}
diff --git
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEncodeContent.java
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEncodeContent.java
index b8da70c754..602b2e8340 100644
---
a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEncodeContent.java
+++
b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEncodeContent.java
@@ -16,25 +16,59 @@
*/
package org.apache.nifi.processors.standard;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.stream.Stream;
+import org.apache.nifi.components.DescribedValue;
+import org.apache.nifi.processor.Relationship;
+import org.apache.nifi.processors.standard.encoding.EncodingMode;
+import org.apache.nifi.processors.standard.encoding.EncodingType;
+import org.apache.nifi.processors.standard.encoding.LineOutputMode;
import org.apache.nifi.util.MockFlowFile;
+import org.apache.nifi.util.StringUtils;
import org.apache.nifi.util.TestRunner;
import org.apache.nifi.util.TestRunners;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.EnumSource;
+import org.junit.jupiter.params.provider.MethodSource;
+
+class TestEncodeContent {
-public class TestEncodeContent {
+ private static final String LOREM_IPSUM = "Lorem ipsum dolor sit amet,
consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua.";
private static final Path FILE_PATH =
Paths.get("src/test/resources/hello.txt");
+ private TestRunner testRunner;
+
+ @BeforeEach
+ void setUp() {
+ testRunner = TestRunners.newTestRunner(EncodeContent.class);
+ }
+
@Test
- public void testBase64RoundTrip() throws IOException {
- final TestRunner testRunner = TestRunners.newTestRunner(new
EncodeContent());
+ void testFailDecodeNotBase64ButIsAMultipleOfFourBytes() {
+ testRunner.setProperty(EncodeContent.MODE, EncodingMode.DECODE);
+ testRunner.setProperty(EncodeContent.ENCODING, EncodingType.BASE64);
- testRunner.setProperty(EncodeContent.MODE, EncodeContent.ENCODE_MODE);
- testRunner.setProperty(EncodeContent.ENCODING,
EncodeContent.BASE64_ENCODING);
+ testRunner.enqueue("four@@@@multiple".getBytes());
+ testRunner.clearTransferState();
+ testRunner.run();
+
+ testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_FAILURE, 1);
+ }
+
+ @ParameterizedTest
+ @EnumSource(value = EncodingType.class)
+ void testRoundTrip(final EncodingType encoding) throws IOException {
+ testRunner.setProperty(EncodeContent.MODE, EncodingMode.ENCODE);
+ testRunner.setProperty(EncodeContent.ENCODING, encoding);
testRunner.enqueue(FILE_PATH);
testRunner.clearTransferState();
@@ -45,7 +79,7 @@ public class TestEncodeContent {
MockFlowFile flowFile =
testRunner.getFlowFilesForRelationship(EncodeContent.REL_SUCCESS).get(0);
testRunner.assertQueueEmpty();
- testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
+ testRunner.setProperty(EncodeContent.MODE, EncodingMode.DECODE);
testRunner.enqueue(flowFile);
testRunner.clearTransferState();
testRunner.run();
@@ -55,12 +89,11 @@ public class TestEncodeContent {
flowFile.assertContentEquals(FILE_PATH);
}
- @Test
- public void testFailDecodeNotBase64() throws IOException {
- final TestRunner testRunner = TestRunners.newTestRunner(new
EncodeContent());
-
- testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
- testRunner.setProperty(EncodeContent.ENCODING,
EncodeContent.BASE64_ENCODING);
+ @ParameterizedTest
+ @EnumSource(value = EncodingType.class)
+ void testDecodeFailure(final EncodingType encoding) throws IOException {
+ testRunner.setProperty(EncodeContent.MODE, EncodingMode.DECODE);
+ testRunner.setProperty(EncodeContent.ENCODING, encoding);
testRunner.enqueue(FILE_PATH);
testRunner.clearTransferState();
@@ -70,96 +103,267 @@ public class TestEncodeContent {
}
@Test
- public void testFailDecodeNotBase64ButIsAMultipleOfFourBytes() {
- final TestRunner testRunner = TestRunners.newTestRunner(new
EncodeContent());
-
- testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
- testRunner.setProperty(EncodeContent.ENCODING,
EncodeContent.BASE64_ENCODING);
+ void testEncodeDecodeSpecialCharsBase64() {
+ final String specialChars = "!@#$%^&*()_+{}:\"<>?[];',./~`-=";
+ final String expectedOutput =
"IUAjJCVeJiooKV8re306Ijw+P1tdOycsLi9+YC09\n";
- testRunner.enqueue("four@@@@multiple".getBytes());
- testRunner.clearTransferState();
- testRunner.run();
+ executeTestSuccessHelper(EncodingMode.ENCODE, EncodingType.BASE64,
specialChars, expectedOutput);
+ testRunner.clearTransferState(); // clear the state for the next test
+ executeTestSuccessHelper(EncodingMode.DECODE, EncodingType.BASE64,
expectedOutput, specialChars);
+ }
- testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_FAILURE, 1);
+ @ParameterizedTest
+ @MethodSource("encodeBase32Args")
+ void testBasicDecodeBase32(final String input, final String
expectedOutput) {
+ // use the same args from `encodeBase32Args`, only flip around input
and output
+ executeTestSuccessHelper(EncodingMode.DECODE, EncodingType.BASE32,
expectedOutput, input);
}
- @Test
- public void testBase32RoundTrip() throws IOException {
- final TestRunner testRunner = TestRunners.newTestRunner(new
EncodeContent());
+ @ParameterizedTest
+ @MethodSource("encodeBase64Args")
+ void testBasicDecodeBase64(final String input, final String
expectedOutput) {
+ // use the same args from `encodeBase64Args`, only flip around input
and output
+ executeTestSuccessHelper(EncodingMode.DECODE, EncodingType.BASE64,
expectedOutput, input);
+ }
- testRunner.setProperty(EncodeContent.MODE, EncodeContent.ENCODE_MODE);
- testRunner.setProperty(EncodeContent.ENCODING,
EncodeContent.BASE32_ENCODING);
+ @ParameterizedTest
+ @MethodSource("encodeHexArgs")
+ void testBasicDecodeHex(final String input, final String expectedOutput) {
+ // use the same args from `encodeHexArgs`, only flip around input and
output
+ executeTestSuccessHelper(EncodingMode.DECODE,
EncodingType.HEXADECIMAL, expectedOutput, input);
+ }
- testRunner.enqueue(FILE_PATH);
- testRunner.clearTransferState();
- testRunner.run();
+ @ParameterizedTest
+ @MethodSource("encodeHexArgs")
+ void testBasicEncodeHex(final String input, final String expectedOutput) {
+ executeTestSuccessHelper(EncodingMode.ENCODE,
EncodingType.HEXADECIMAL, input, expectedOutput);
+ }
- testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_SUCCESS, 1);
+ private static Stream<Arguments> encodeHexArgs() {
+ return Stream.of(
+ Arguments.of("hello", "68656C6C6F"),
+ Arguments.of("foo", "666F6F"),
+ Arguments.of("你好", "E4BDA0E5A5BD"),
+ Arguments.of("Здравствуйте",
"D097D0B4D180D0B0D0B2D181D182D0B2D183D0B9D182D0B5")
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("encodeBase32Args")
+ void testBasicEncodeBase32(final String input, final String
expectedOutput) {
+ executeTestSuccessHelper(EncodingMode.ENCODE, EncodingType.BASE32,
input, expectedOutput);
+ }
- MockFlowFile flowFile =
testRunner.getFlowFilesForRelationship(EncodeContent.REL_SUCCESS).get(0);
- testRunner.assertQueueEmpty();
+ private static Stream<Arguments> encodeBase32Args() {
+ return Stream.of(
+ Arguments.of("hello", "NBSWY3DP\n"),
+ Arguments.of("foo", "MZXW6===\n"),
+ Arguments.of("你好", "4S62BZNFXU======\n"),
+ Arguments.of("Здравствуйте",
"2CL5BNGRQDILBUFS2GA5DAWQWLIYHUFZ2GBNBNI=\n")
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("encodeBase64Args")
+ void testBasicEncodeBase64(final String input, final String
expectedOutput) {
+ executeTestSuccessHelper(EncodingMode.ENCODE, EncodingType.BASE64,
input, expectedOutput);
+ }
- testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
- testRunner.enqueue(flowFile);
- testRunner.clearTransferState();
- testRunner.run();
- testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_SUCCESS, 1);
+ private static Stream<Arguments> encodeBase64Args() {
+ return Stream.of(
+ Arguments.of("hello", "aGVsbG8=\n"),
+ Arguments.of("foo", "Zm9v\n"),
+ Arguments.of("你好", "5L2g5aW9\n"),
+ Arguments.of("Здравствуйте",
"0JfQtNGA0LDQstGB0YLQstGD0LnRgtC1\n")
+ );
+ }
- flowFile =
testRunner.getFlowFilesForRelationship(EncodeContent.REL_SUCCESS).get(0);
- flowFile.assertContentEquals(FILE_PATH);
+ @Test
+ void testBlankValueShouldNotFail() {
+ executeTestSuccessHelper(EncodingMode.ENCODE,
+ EncodingType.BASE64,
+ StringUtils.EMPTY,
+ StringUtils.EMPTY);
}
@Test
- public void testFailDecodeNotBase32() throws IOException {
- final TestRunner testRunner = TestRunners.newTestRunner(new
EncodeContent());
+ void testEncodeContentMultipleLinesBase64() {
+ // this input is greater than 57 bytes, sure to generate multiple
lines in base64
+ final String expectedOutput =
"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwg\n"
+ +
"c2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWdu\n"
+ + "YSBhbGlxdWEu\n";
+
+ // Execute the test using the helper method
+ executeTestHelper(EncodingMode.ENCODE,
+ EncodingType.BASE64,
+ LOREM_IPSUM,
+ LineOutputMode.MULTIPLE_LINES,
+ expectedOutput,
+ EncodeContent.REL_SUCCESS);
+ }
- testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
- testRunner.setProperty(EncodeContent.ENCODING,
EncodeContent.BASE32_ENCODING);
+ @Test
+ void testEncodeContentSingleLineBase64() {
+ // this input is greater than 57 bytes, sure to generate multiple
lines in base64
+ final String expectedOutput =
"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwg"
+ +
"c2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWdu"
+ + "YSBhbGlxdWEu";
+
+ // Execute the test using the helper method
+ executeTestHelper(EncodingMode.ENCODE,
+ EncodingType.BASE64,
+ LOREM_IPSUM,
+ LineOutputMode.SINGLE_LINE,
+ expectedOutput,
+ EncodeContent.REL_SUCCESS);
+ }
- testRunner.enqueue(FILE_PATH);
- testRunner.clearTransferState();
- testRunner.run();
+ @Test
+ void testEncodeContentSingleLineBase32() {
+ // this input is greater than 57 bytes, sure to generate multiple
lines in base64
+ final String expectedOutput =
"JRXXEZLNEBUXA43VNUQGI33MN5ZCA43JOQQGC3LFOQWCAY3PNZZWKY3UMV2HK4RAMFSGS4DJONRWS3THEBSWY2LUF"
+ +
"QQHGZLEEBSG6IDFNF2XG3LPMQQHIZLNOBXXEIDJNZRWSZDJMR2W45BAOV2CA3DBMJXXEZJAMV2CAZDPNRXXEZJANVQWO3TBEBQWY2LROVQS4===";
+
+ // Execute the test using the helper method
+ executeTestHelper(EncodingMode.ENCODE,
+ EncodingType.BASE32,
+ LOREM_IPSUM,
+ LineOutputMode.SINGLE_LINE,
+ expectedOutput,
+ EncodeContent.REL_SUCCESS);
+ }
- testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_FAILURE, 1);
+ @Test
+ void testEncodeContentMultipleLinesBase32() {
+ // this input is greater than 57 bytes, sure to generate multiple
lines in base64
+ final String expectedOutput =
"JRXXEZLNEBUXA43VNUQGI33MN5ZCA43JOQQGC3LFOQWCAY3PNZZWKY3UMV2HK4RAMFSGS4DJ\n"
+ +
"ONRWS3THEBSWY2LUFQQHGZLEEBSG6IDFNF2XG3LPMQQHIZLNOBXXEIDJNZRWSZDJMR2W45BA\n"
+ + "OV2CA3DBMJXXEZJAMV2CAZDPNRXXEZJANVQWO3TBEBQWY2LROVQS4===\n";
+
+ // Execute the test using the helper method
+ executeTestHelper(EncodingMode.ENCODE,
+ EncodingType.BASE32,
+ LOREM_IPSUM,
+ LineOutputMode.MULTIPLE_LINES, // set false to output multiple
lines
+ expectedOutput,
+ EncodeContent.REL_SUCCESS);
}
@Test
- public void testHexRoundTrip() throws IOException {
- final TestRunner testRunner = TestRunners.newTestRunner(new
EncodeContent());
+ void testEncodeContentMultipleLinesNonStandardLengthBase32() {
+ // this input is greater than 57 bytes, sure to generate multiple
lines in base64
+ final String expectedOutput =
"JRXXEZLNEBUXA43VNUQGI33MN5ZCA43JOQQGC3LFOQWCAY3PNZZWKY3UMV2HK4RAMFSGS4DJONRWS3TH\n"
+ +
"EBSWY2LUFQQHGZLEEBSG6IDFNF2XG3LPMQQHIZLNOBXXEIDJNZRWSZDJMR2W45BAOV2CA3DBMJXXEZJA\n"
+ + "MV2CAZDPNRXXEZJANVQWO3TBEBQWY2LROVQS4===\n";
+
+ // Execute the test using the helper method
+ executeTestHelper(EncodingMode.ENCODE,
+ EncodingType.BASE32,
+ LOREM_IPSUM,
+ LineOutputMode.MULTIPLE_LINES,
+ 80,
+ expectedOutput,
+ EncodeContent.REL_SUCCESS);
+ }
- testRunner.setProperty(EncodeContent.MODE, EncodeContent.ENCODE_MODE);
- testRunner.setProperty(EncodeContent.ENCODING,
EncodeContent.HEX_ENCODING);
+ @Test
+ void testThatLineLengthIsIgnoredIfSingleLineOutputTrueBase32() {
+ // this input is greater than 57 bytes, sure to generate multiple
lines in base64
+ final String expectedOutput =
"JRXXEZLNEBUXA43VNUQGI33MN5ZCA43JOQQGC3LFOQWCAY3PNZZWKY3UMV2HK4RAMFSGS4DJONRWS3THEBSWY2LUFQQHGZLEEB"
+ +
"SG6IDFNF2XG3LPMQQHIZLNOBXXEIDJNZRWSZDJMR2W45BAOV2CA3DBMJXXEZJAMV2CAZDPNRXXEZJANVQWO3TBEBQWY2LROVQS4===";
+
+ // Setting a low value for `lineLength` but single line true ensures
that `lineLength` is ignored
+ executeTestHelper(EncodingMode.ENCODE,
+ EncodingType.BASE32,
+ LOREM_IPSUM,
+ LineOutputMode.SINGLE_LINE,
+ 2, // set a low value >= 0
+ expectedOutput,
+ EncodeContent.REL_SUCCESS);
+ }
- testRunner.enqueue(FILE_PATH);
- testRunner.clearTransferState();
- testRunner.run();
+ @Test
+ void testEncodeContentMultipleLinesNonStandardLengthBase64() {
+ // this input is greater than 57 bytes, sure to generate multiple
lines in base64
+ final String expectedOutput =
"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwgc2Vk\n"
+ +
"IGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWduYSBhbGlx\n"
+ + "dWEu\n";
+
+ // Execute the test using the helper method
+ executeTestHelper(EncodingMode.ENCODE,
+ EncodingType.BASE64,
+ LOREM_IPSUM,
+ LineOutputMode.MULTIPLE_LINES, // set false to output multiple
lines
+ 80,
+ expectedOutput,
+ EncodeContent.REL_SUCCESS);
+ }
- testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_SUCCESS, 1);
+ @Test
+ void testThatLineLengthIsIgnoredIfSingleLineOutputTrueBase64() {
+ // this input is greater than 57 bytes, sure to generate multiple
lines in base64
+ final String expectedOutput =
"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdCwg"
+ +
"c2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0IGRvbG9yZSBtYWdu"
+ + "YSBhbGlxdWEu";
+
+ // Setting a low value for `lineLength` but single line true ensures
that `lineLength` is ignored
+ executeTestHelper(EncodingMode.ENCODE,
+ EncodingType.BASE64,
+ LOREM_IPSUM,
+ LineOutputMode.SINGLE_LINE, // set true to output single line
+ 2, // set a low value >= 0
+ expectedOutput,
+ EncodeContent.REL_SUCCESS);
+ }
- MockFlowFile flowFile =
testRunner.getFlowFilesForRelationship(EncodeContent.REL_SUCCESS).get(0);
- testRunner.assertQueueEmpty();
+ private void executeTestSuccessHelper(final DescribedValue mode,
+ final DescribedValue encodingType,
+ final String input,
+ final String expectedOutput) {
+ executeTestSuccessHelper(mode, encodingType, input,
LineOutputMode.MULTIPLE_LINES, expectedOutput);
+ }
- testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
- testRunner.enqueue(flowFile);
- testRunner.clearTransferState();
- testRunner.run();
- testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_SUCCESS, 1);
+ private void executeTestSuccessHelper(final DescribedValue mode,
+ final DescribedValue encodingType,
+ final String input,
+ final DescribedValue outputToSingleLine,
+ final String expectedOutput) {
+ executeTestHelper(mode, encodingType, input, outputToSingleLine,
expectedOutput, EncodeContent.REL_SUCCESS);
+ }
- flowFile =
testRunner.getFlowFilesForRelationship(EncodeContent.REL_SUCCESS).get(0);
- flowFile.assertContentEquals(FILE_PATH);
+ private void executeTestHelper(final DescribedValue mode,
+ final DescribedValue encodingType,
+ final String input,
+ final DescribedValue outputToSingleLine,
+ final String expectedOutput,
+ final Relationship routedTo) {
+ executeTestHelper(mode,
+ encodingType,
+ input,
+ outputToSingleLine,
+ 76,
+ expectedOutput,
+ routedTo);
}
- @Test
- public void testFailDecodeNotHex() throws IOException {
- final TestRunner testRunner = TestRunners.newTestRunner(new
EncodeContent());
+ private void executeTestHelper(final DescribedValue mode,
+ final DescribedValue encodingType,
+ final String input,
+ final DescribedValue outputToSingleLine,
+ final Integer lineLength,
+ final String expectedOutput,
+ final Relationship routedTo) {
- testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
- testRunner.setProperty(EncodeContent.ENCODING,
EncodeContent.HEX_ENCODING);
+ testRunner.setProperty(EncodeContent.MODE, mode);
+ testRunner.setProperty(EncodeContent.ENCODING, encodingType);
+ testRunner.setProperty(EncodeContent.LINE_OUTPUT_MODE,
outputToSingleLine);
+ testRunner.setProperty(EncodeContent.ENCODED_LINE_LENGTH,
Integer.toString(lineLength));
- testRunner.enqueue(FILE_PATH);
- testRunner.clearTransferState();
+ testRunner.enqueue(input);
testRunner.run();
- testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_FAILURE, 1);
+ final MockFlowFile result =
testRunner.getFlowFilesForRelationship(routedTo).get(0);
+ assertEquals(expectedOutput, result.getContent());
+ testRunner.assertAllFlowFilesTransferred(routedTo, 1);
}
}