mirror of https://github.com/apache/nifi.git
NIFI-12017 Added Line Length Properties to EncodeContent
This closes #8417 Signed-off-by: David Handermann <exceptionfactory@apache.org>
This commit is contained in:
parent
83bc0e5453
commit
5cc857b99c
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue