Skip to content
This repository has been archived by the owner on Jan 27, 2025. It is now read-only.

Implement "strict" mode. #210

Merged
merged 3 commits into from
Mar 31, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ package-lock.json
/metafix/src/test/resources/org/metafacture/metafix/integration/**/*.err
/metafix/src/test/resources/org/metafacture/metafix/integration/**/*.out
/metafix/src/test/resources/org/metafacture/metafix/integration/**/output-*
!/metafix/src/test/resources/org/metafacture/metafix/integration/**/expected.err
2 changes: 1 addition & 1 deletion metafix/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ dependencies {
implementation "org.metafacture:metamorph:${versions.metafacture}"

testImplementation "nl.jqno.equalsverifier:equalsverifier:${versions.equalsverifier}"
testImplementation "org.mockito:mockito-core:${versions.mockito}"
testImplementation "org.mockito:mockito-inline:${versions.mockito}"
testImplementation "org.mockito:mockito-junit-jupiter:${versions.mockito}"
}

Expand Down
96 changes: 61 additions & 35 deletions metafix/integrationTest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ todo_file=todo.txt

input_glob=input.*
expected_glob=expected.*
expected_errors_extension=err

metafix_output_glob=output-metafix.*
catmandu_output_glob=output-catmandu.*
Expand Down Expand Up @@ -102,6 +103,8 @@ function get_file() {
reason="Ambiguous $type files: $*"
elif [ ! -r "$1" ]; then
reason="No $type file: $1"
elif [ "$type" != "output" ] && [ ! -s "$1" ]; then
reason="Empty $type file: $1"
else
current_file=$1
return 0
Expand Down Expand Up @@ -138,6 +141,40 @@ function skip_test() {
fi
}

function test_passed() {
if [ -r "$2" ]; then
log "$color_test$1$color_reset: ${color_failed}FAILED$color_reset (Marked as \"to do\", but passed.)"

((failed++)) || true
else
if parse_boolean "$METAFIX_LOG_PASSED"; then
log "$color_test$1$color_reset: ${color_passed}PASSED$color_reset$3"
fi

((passed++)) || true
fi
}

function test_failed() {
if ! skip_test "$1" "$2"; then
log "$color_test$1$color_reset: $color_failed$4$color_reset$3"

if [ $# -ge 13 ]; then
log " Fix: $9"
log " Input: ${10}"
log " Expected: ${11}"
log " Output: ${12}"
log " Diff: ${13}"

[ -s "${13}" ] && $colordiff <"${13}" || rm -f "${13}"
fi

command_info "$5" "$6" "$7" "$8"

((failed++)) || true
fi
}

function run_tests() {
local test matched=1\
test_directory test_fix test_input test_expected test_todo\
Expand Down Expand Up @@ -165,62 +202,51 @@ function run_tests() {
test_todo="$test_directory/$todo_file"

if [ -z "$disable_todo" ] || ! skip_test "$test" "$test_todo"; then
# TODO: catmandu (optional)

metafix_command_output="$test_directory/metafix.out"
metafix_command_error="$test_directory/metafix.err"

metafix_start_time=$(current_time)

# TODO: catmandu (optional)
run_metafix "$test_directory/$metafix_file" >"$metafix_command_output" 2>"$metafix_command_error"
metafix_exit_status=$?

if run_metafix "$test_directory/$metafix_file" >"$metafix_command_output" 2>"$metafix_command_error"; then
metafix_exit_status=$?
metafix_elapsed_time=$(elapsed_time "$metafix_start_time")

if [ "$metafix_exit_status" -eq 0 ]; then
if get_file "$test" output "$test_directory"/$metafix_output_glob; then
metafix_output=$current_file
metafix_diff="$test_directory/metafix.diff"

metafix_elapsed_time=$(elapsed_time "$metafix_start_time")

if diff -u "$test_expected" "$metafix_output" >"$metafix_diff"; then
if [ -r "$test_todo" ]; then
log "$color_test$test$color_reset: ${color_failed}FAILED$color_reset (Marked as \"to do\", but passed.)"

((failed++)) || true
else
if parse_boolean "$METAFIX_LOG_PASSED"; then
log "$color_test$test$color_reset: ${color_passed}PASSED$color_reset$metafix_elapsed_time"
fi

((passed++)) || true
fi
test_passed "$test" "$test_todo" "$metafix_elapsed_time"

rm -f "$metafix_diff" "$metafix_command_output" "$metafix_command_error"
elif ! skip_test "$test" "$test_todo"; then
log "$color_test$test$color_reset: ${color_failed}FAILED$color_reset$metafix_elapsed_time"

log " Fix: $test_fix"
log " Input: $test_input"
log " Expected: $test_expected"
log " Output: $metafix_output"
log " Diff: $metafix_diff"

[ -s "$metafix_diff" ] && $colordiff <"$metafix_diff" || rm -f "$metafix_diff"

command_info metafix "$metafix_exit_status" "$metafix_command_output" "$metafix_command_error"

((failed++)) || true
else
test_failed "$test" "$test_todo" "$metafix_elapsed_time" FAILED\
metafix "$metafix_exit_status" "$metafix_command_output" "$metafix_command_error"\
"$test_fix" "$test_input" "$test_expected" "$metafix_output" "$metafix_diff"
fi
else
command_info metafix "$metafix_exit_status" "$metafix_command_output" "$metafix_command_error"
fi
elif ! skip_test "$test" "$test_todo"; then
metafix_exit_status=$?
elif [ "${test_expected##*.}" == "$expected_errors_extension" ]; then
get_file "$test" error "$metafix_command_error" || { log; continue; }

log "$color_test$test$color_reset: ${color_error}ERROR$color_reset"
while read -r pattern; do
if ! grep -qE "$pattern" "$metafix_command_error"; then
test_failed "$test" "$test_todo" " (Pattern not found: $pattern)" FAILED\
metafix "$metafix_exit_status" "$metafix_command_output" "$metafix_command_error"

command_info metafix "$metafix_exit_status" "$metafix_command_output" "$metafix_command_error"
continue 2
fi
done <"$test_expected"

((failed++)) || true
test_passed "$test" "$test_todo" "$metafix_elapsed_time"
else
test_failed "$test" "$test_todo" "$metafix_elapsed_time" ERROR\
metafix "$metafix_exit_status" "$metafix_command_output" "$metafix_command_error"
fi
fi
done
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@

import org.metafacture.framework.MetafactureException;

/**
* Indicates dynamic (i.e., data-dependent) issues during Fix execution that
* should be subject to {@link Metafix.Strictness strictness} handling.
*
* @see FixProcessException
*/
public class FixExecutionException extends MetafactureException {

public FixExecutionException(final String message) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2022 hbz NRW
*
* Licensed 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.metafacture.metafix;

import org.metafacture.framework.MetafactureException;

/**
* Indicates static (i.e., data-independent) issues with the usage of Fix
* expressions.
*
* @see FixExecutionException
*/
public class FixProcessException extends MetafactureException {

public FixProcessException(final String message) {
super(message);
}

public FixProcessException(final String message, final Throwable cause) {
super(message, cause);
}

}
58 changes: 58 additions & 0 deletions metafix/src/main/java/org/metafacture/metafix/Metafix.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;

/**
* Transforms a data stream sent via the {@link StreamReceiver} interface. Use
Expand All @@ -61,6 +62,8 @@ public class Metafix implements StreamPipe<StreamReceiver>, Maps { // checkstyle
public static final String VAR_END = "]";
public static final String VAR_START = "$[";

public static final Strictness DEFAULT_STRICTNESS = Strictness.PROCESS;

public static final Map<String, String> NO_VARS = Collections.emptyMap();

private static final Logger LOG = LoggerFactory.getLogger(Metafix.class);
Expand All @@ -79,6 +82,7 @@ public class Metafix implements StreamPipe<StreamReceiver>, Maps { // checkstyle
private List<Value> entities = new ArrayList<>();
private Record currentRecord = new Record();
private StreamReceiver outputStreamReceiver;
private Strictness strictness = DEFAULT_STRICTNESS;
private String fixFile;
private String recordIdentifier;
private int entityCount;
Expand Down Expand Up @@ -325,4 +329,58 @@ public String putValue(final String mapName, final String key, final String valu
return maps.computeIfAbsent(mapName, k -> new HashMap<>()).put(key, value);
}

public void setStrictness(final Strictness strictness) {
this.strictness = strictness != null ? strictness : DEFAULT_STRICTNESS;
}

public Strictness getStrictness() {
return strictness;
}

public enum Strictness {

/**
* Aborts process by throwing an exception.
*/
PROCESS {
@Override
protected void handleInternal(final FixExecutionException exception, final Record record) {
throw exception;
}
},

/**
* Ignores (skips) record and logs an error.
*/
RECORD {
@Override
protected void handleInternal(final FixExecutionException exception, final Record record) {
log(exception, LOG::error);
record.setReject(true); // TODO: Skip remaining expressions?
}
},

/**
* Ignores (skips) expression and logs a warning.
*/
EXPRESSION {
@Override
protected void handleInternal(final FixExecutionException exception, final Record record) {
log(exception, LOG::warn);
}
};

public void handle(final FixExecutionException exception, final Record record) {
LOG.debug("Current record: {}", record);
handleInternal(exception, record);
}

protected abstract void handleInternal(FixExecutionException exception, Record record);

protected void log(final FixExecutionException exception, final BiConsumer<String, Throwable> logger) {
logger.accept(exception.getMessage(), exception.getCause());
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ else if (e instanceof MethodCall) {
processFunction((MethodCall) e, params);
}
else {
throw new FixExecutionException(executionExceptionMessage(e));
throw new FixProcessException(executionExceptionMessage(e));
}
});
}
Expand Down Expand Up @@ -173,15 +173,26 @@ private void processExpression(final Expression expression, final Consumer<Strin
}

private void processFix(final Supplier<String> messageSupplier, final Runnable runnable) {
final FixExecutionException exception;

try {
runnable.run();
return;
}
catch (final FixExecutionException e) {
catch (final FixProcessException e) {
throw e; // TODO: Add nesting information?
}
catch (final FixExecutionException e) {
exception = e; // TODO: Add nesting information?
}
catch (final IllegalStateException | NumberFormatException e) {
exception = new FixExecutionException(messageSupplier.get(), e);
}
catch (final RuntimeException e) { // checkstyle-disable-line IllegalCatch
throw new FixExecutionException(messageSupplier.get(), e);
throw new FixProcessException(messageSupplier.get(), e);
}

metafix.getStrictness().handle(exception, record);
}

private String executionExceptionMessage(final Expression expression) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ public void shouldLookupInSeparateExternalFileMap() {
public void shouldNotLookupInRelativeExternalFileMapFromInlineScript() {
final String mapFile = "../maps/test.csv";

MetafixTestHelpers.assertThrowsCause(IllegalArgumentException.class, "Cannot resolve relative path: " + mapFile, () ->
MetafixTestHelpers.assertProcessException(IllegalArgumentException.class, "Cannot resolve relative path: " + mapFile, () ->
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
LOOKUP + " '" + mapFile + "')"
),
Expand Down Expand Up @@ -299,7 +299,7 @@ public void shouldNotLookupInUnknownInternalMap() {

@Test
public void shouldFailLookupInUnknownExternalMap() {
MetafixTestHelpers.assertThrowsCause(MorphExecutionException.class, "File not found: testMap.csv", () ->
MetafixTestHelpers.assertProcessException(MorphExecutionException.class, "File not found: testMap.csv", () ->
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
LOOKUP + " 'testMap.csv')"
),
Expand Down
Loading