NIFI-12017 Added Line Length Properties to EncodeContent

This closes #8417

Signed-off-by: David Handermann <exceptionfactory@apache.org>
This commit is contained in:
knguyen 2024-02-15 19:35:13 +00:00 committed by exceptionfactory
parent 83bc0e5453
commit 5cc857b99c
No known key found for this signature in database
5 changed files with 528 additions and 128 deletions

View File

@ -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(BASE64_ENCODING, BASE32_ENCODING, HEX_ENCODING)
.defaultValue(BASE64_ENCODING)
.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)
.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 Set<Relationship> relationships = Set.of(REL_SUCCESS,
REL_FAILURE);
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);
@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;
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -16,65 +16,46 @@
*/
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;
public class TestEncodeContent {
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");
@Test
public void testBase64RoundTrip() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EncodeContent());
private TestRunner testRunner;
testRunner.setProperty(EncodeContent.MODE, EncodeContent.ENCODE_MODE);
testRunner.setProperty(EncodeContent.ENCODING, EncodeContent.BASE64_ENCODING);
testRunner.enqueue(FILE_PATH);
testRunner.clearTransferState();
testRunner.run();
testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_SUCCESS, 1);
MockFlowFile flowFile = testRunner.getFlowFilesForRelationship(EncodeContent.REL_SUCCESS).get(0);
testRunner.assertQueueEmpty();
testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
testRunner.enqueue(flowFile);
testRunner.clearTransferState();
testRunner.run();
testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_SUCCESS, 1);
flowFile = testRunner.getFlowFilesForRelationship(EncodeContent.REL_SUCCESS).get(0);
flowFile.assertContentEquals(FILE_PATH);
@BeforeEach
void setUp() {
testRunner = TestRunners.newTestRunner(EncodeContent.class);
}
@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);
testRunner.enqueue(FILE_PATH);
testRunner.clearTransferState();
testRunner.run();
testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_FAILURE, 1);
}
@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 testFailDecodeNotBase64ButIsAMultipleOfFourBytes() {
testRunner.setProperty(EncodeContent.MODE, EncodingMode.DECODE);
testRunner.setProperty(EncodeContent.ENCODING, EncodingType.BASE64);
testRunner.enqueue("four@@@@multiple".getBytes());
testRunner.clearTransferState();
@ -83,12 +64,11 @@ public class TestEncodeContent {
testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_FAILURE, 1);
}
@Test
public void testBase32RoundTrip() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EncodeContent());
testRunner.setProperty(EncodeContent.MODE, EncodeContent.ENCODE_MODE);
testRunner.setProperty(EncodeContent.ENCODING, EncodeContent.BASE32_ENCODING);
@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();
@ -99,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();
@ -109,12 +89,11 @@ public class TestEncodeContent {
flowFile.assertContentEquals(FILE_PATH);
}
@Test
public void testFailDecodeNotBase32() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EncodeContent());
testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
testRunner.setProperty(EncodeContent.ENCODING, EncodeContent.BASE32_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();
@ -124,42 +103,267 @@ public class TestEncodeContent {
}
@Test
public void testHexRoundTrip() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EncodeContent());
void testEncodeDecodeSpecialCharsBase64() {
final String specialChars = "!@#$%^&*()_+{}:\"<>?[];',./~`-=";
final String expectedOutput = "IUAjJCVeJiooKV8re306Ijw+P1tdOycsLi9+YC09\n";
testRunner.setProperty(EncodeContent.MODE, EncodeContent.ENCODE_MODE);
testRunner.setProperty(EncodeContent.ENCODING, EncodeContent.HEX_ENCODING);
executeTestSuccessHelper(EncodingMode.ENCODE, EncodingType.BASE64, specialChars, expectedOutput);
testRunner.clearTransferState(); // clear the state for the next test
executeTestSuccessHelper(EncodingMode.DECODE, EncodingType.BASE64, expectedOutput, specialChars);
}
testRunner.enqueue(FILE_PATH);
testRunner.clearTransferState();
testRunner.run();
@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);
}
testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_SUCCESS, 1);
@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);
}
MockFlowFile flowFile = testRunner.getFlowFilesForRelationship(EncodeContent.REL_SUCCESS).get(0);
testRunner.assertQueueEmpty();
@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.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
testRunner.enqueue(flowFile);
testRunner.clearTransferState();
testRunner.run();
testRunner.assertAllFlowFilesTransferred(EncodeContent.REL_SUCCESS, 1);
@ParameterizedTest
@MethodSource("encodeHexArgs")
void testBasicEncodeHex(final String input, final String expectedOutput) {
executeTestSuccessHelper(EncodingMode.ENCODE, EncodingType.HEXADECIMAL, input, expectedOutput);
}
flowFile = testRunner.getFlowFilesForRelationship(EncodeContent.REL_SUCCESS).get(0);
flowFile.assertContentEquals(FILE_PATH);
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);
}
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);
}
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")
);
}
@Test
void testBlankValueShouldNotFail() {
executeTestSuccessHelper(EncodingMode.ENCODE,
EncodingType.BASE64,
StringUtils.EMPTY,
StringUtils.EMPTY);
}
@Test
public void testFailDecodeNotHex() 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";
testRunner.setProperty(EncodeContent.MODE, EncodeContent.DECODE_MODE);
testRunner.setProperty(EncodeContent.ENCODING, EncodeContent.HEX_ENCODING);
// Execute the test using the helper method
executeTestHelper(EncodingMode.ENCODE,
EncodingType.BASE64,
LOREM_IPSUM,
LineOutputMode.MULTIPLE_LINES,
expectedOutput,
EncodeContent.REL_SUCCESS);
}
testRunner.enqueue(FILE_PATH);
testRunner.clearTransferState();
@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);
}
@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);
}
@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
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);
}
@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);
}
@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);
}
@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);
}
private void executeTestSuccessHelper(final DescribedValue mode,
final DescribedValue encodingType,
final String input,
final String expectedOutput) {
executeTestSuccessHelper(mode, encodingType, input, LineOutputMode.MULTIPLE_LINES, expectedOutput);
}
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);
}
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);
}
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, mode);
testRunner.setProperty(EncodeContent.ENCODING, encodingType);
testRunner.setProperty(EncodeContent.LINE_OUTPUT_MODE, outputToSingleLine);
testRunner.setProperty(EncodeContent.ENCODED_LINE_LENGTH, Integer.toString(lineLength));
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);
}
}