summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJim Hahn <jrh3@att.com>2018-02-07 17:13:32 -0500
committerJim Hahn <jrh3@att.com>2018-02-08 10:32:53 -0500
commite9fd35a303a5f5f41726c3216c8acd7598a3a494 (patch)
tree8793c41d46c0e5a1bf0101bae64f238123af931f
parent82bc8f543e578f32201d07a23b42d8539b89a4f1 (diff)
Add ExtractAppender to facilite junit tests
Added ExtractAppender to provide a way for junit tests to capture data sent to a logger. Changed logback.version to 1.2.3 and moved the property to the top-level pom. Updated license date in top-level pom. Refactored ExceptionsText, adding ErrorsTester and ThrowablesTester classes to reduce sonar issues. Change-Id: Ief7d08972bf4e7037b59c2afe4b77b252f2ad60a Issue-ID: POLICY-582 Signed-off-by: Jim Hahn <jrh3@att.com>
-rw-r--r--pom.xml3
-rw-r--r--utils-test/pom.xml5
-rw-r--r--utils-test/src/main/java/org/onap/policy/common/utils/test/ConstructionError.java58
-rw-r--r--utils-test/src/main/java/org/onap/policy/common/utils/test/ErrorsTester.java46
-rw-r--r--utils-test/src/main/java/org/onap/policy/common/utils/test/ExceptionsTester.java490
-rw-r--r--utils-test/src/main/java/org/onap/policy/common/utils/test/ThrowablesTester.java515
-rw-r--r--utils-test/src/main/java/org/onap/policy/common/utils/test/log/logback/ExtractAppender.java191
-rw-r--r--utils-test/src/test/java/org/onap/policy/common/utils/test/ConstructionErrorTest.java37
-rw-r--r--utils-test/src/test/java/org/onap/policy/common/utils/test/ErrorsTesterTest.java77
-rw-r--r--utils-test/src/test/java/org/onap/policy/common/utils/test/ExceptionsTesterTest.java110
-rw-r--r--utils-test/src/test/java/org/onap/policy/common/utils/test/ThrowablesTesterTest.java216
-rw-r--r--utils-test/src/test/java/org/onap/policy/common/utils/test/log/logback/ExtractAppenderTest.java484
-rw-r--r--utils-test/src/test/resources/logback-test.xml37
13 files changed, 1722 insertions, 547 deletions
diff --git a/pom.xml b/pom.xml
index 67454f39..cd37e22e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -2,7 +2,7 @@
============LICENSE_START=======================================================
ONAP Policy Engine - Drools PDP
================================================================================
- Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
================================================================================
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -41,6 +41,7 @@
<properties>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
+ <logback.version>1.2.3</logback.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<nexusproxy>https://nexus.onap.org</nexusproxy>
<sitePath>/content/sites/site/${project.groupId}/${project.artifactId}/${project.version}</sitePath>
diff --git a/utils-test/pom.xml b/utils-test/pom.xml
index f9b314f6..31a27367 100644
--- a/utils-test/pom.xml
+++ b/utils-test/pom.xml
@@ -38,6 +38,11 @@
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
+ <dependency>
+ <groupId>ch.qos.logback</groupId>
+ <artifactId>logback-classic</artifactId>
+ <version>${logback.version}</version>
+ </dependency>
</dependencies>
<build>
diff --git a/utils-test/src/main/java/org/onap/policy/common/utils/test/ConstructionError.java b/utils-test/src/main/java/org/onap/policy/common/utils/test/ConstructionError.java
new file mode 100644
index 00000000..336dc602
--- /dev/null
+++ b/utils-test/src/main/java/org/onap/policy/common/utils/test/ConstructionError.java
@@ -0,0 +1,58 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Integrity Audit
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.test;
+
+/**
+ * An error that occurred while trying to construct an object for a junit test.
+ */
+public class ConstructionError extends AssertionError {
+ private static final long serialVersionUID = 1L;
+
+ /**
+ *
+ */
+ public ConstructionError() {
+ super();
+ }
+
+ /**
+ * @param message
+ */
+ public ConstructionError(String message) {
+ super(message);
+ }
+
+ /**
+ * @param cause
+ */
+ public ConstructionError(Throwable cause) {
+ super(cause);
+ }
+
+ /**
+ * @param message
+ * @param cause
+ */
+ public ConstructionError(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/utils-test/src/main/java/org/onap/policy/common/utils/test/ErrorsTester.java b/utils-test/src/main/java/org/onap/policy/common/utils/test/ErrorsTester.java
new file mode 100644
index 00000000..12b48442
--- /dev/null
+++ b/utils-test/src/main/java/org/onap/policy/common/utils/test/ErrorsTester.java
@@ -0,0 +1,46 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Integrity Monitor
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.test;
+
+/**
+ * Used to test various Error subclasses. Uses reflection to identify the
+ * constructors that the subclass supports.
+ */
+public class ErrorsTester extends ThrowablesTester {
+
+ /**
+ * Runs tests, on an Error subclass, for all of the standard constructors.
+ * If the Error subclass does not support a given type of constructor, then
+ * it skips that test. Does <i>not</i> throw an exception if no standard
+ * constructors are found.
+ *
+ * @param claz
+ * subclass to be tested
+ * @return the number of constructors that were found/tested
+ * @throws ConstructionError
+ * if the Error subclass cannot be constructed
+ * @throws AssertionError
+ * if the constructed objects fail to pass various tests
+ */
+ public <T extends Error> int testError(Class<T> claz) {
+ return testThrowable(claz);
+ }
+}
diff --git a/utils-test/src/main/java/org/onap/policy/common/utils/test/ExceptionsTester.java b/utils-test/src/main/java/org/onap/policy/common/utils/test/ExceptionsTester.java
index 8705c48c..156fca89 100644
--- a/utils-test/src/main/java/org/onap/policy/common/utils/test/ExceptionsTester.java
+++ b/utils-test/src/main/java/org/onap/policy/common/utils/test/ExceptionsTester.java
@@ -22,7 +22,6 @@ package org.onap.policy.common.utils.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Constructor;
@@ -31,7 +30,7 @@ import java.lang.reflect.Constructor;
* Used to test various Exception subclasses. Uses reflection to identify the
* constructors that the subclass supports.
*/
-public class ExceptionsTester {
+public class ExceptionsTester extends ThrowablesTester {
/**
* Runs tests, on an Exception subclass, for all of the standard
@@ -40,144 +39,43 @@ public class ExceptionsTester {
*
* @param claz
* subclass to be tested
- * @return the number of constructors that the test found/tested
- * @throws Exception
- * if the Exception cannot be constructed
+ * @return the number of constructors that were found/tested
+ * @throws ConstructionError
+ * if the Exception subclass cannot be constructed
+ * @throws AssertionError
+ * if the constructed objects fail to pass various tests
*/
- public <T extends Exception> int test(Class<T> claz) throws Exception {
- int ncons = 0;
+ public <T extends Exception> int test(Class<T> claz) {
+ int ncons = testException(claz);
- ncons += testDefault(claz);
- ncons += testString(claz);
- ncons += testThrowable(claz);
- ncons += testException(claz);
- ncons += testStringThrowable(claz);
- ncons += testStringException(claz);
- ncons += testStringThrowableBooleanBoolean(claz);
- ncons += testStringExceptionBooleanBoolean(claz);
-
assertTrue(ncons > 0);
return ncons;
}
/**
- * Tests exceptions created via the default constructor. Verifies that:
- * <ul>
- * <li><i>toString()</i> returns a non-null value</li>
- * <li><i>getMessage()</i> returns null</li>
- * <li><i>getCause()</i> returns null</li>
- * </ul>
- *
- * If the Exception subclass does not support this type of constructor, then
- * this method simply returns.
- *
- * @param claz
- * subclass to be tested
- * @return {@code 1}, if the subclass supports this type of constructor,
- * {@code 0} otherwise
- * @throws Exception
- * if the Exception cannot be constructed
- */
- public <T extends Exception> int testDefault(Class<T> claz) throws Exception {
- Constructor<T> cons;
-
- try {
- cons = claz.getConstructor();
-
- } catch (NoSuchMethodException | SecurityException e) {
- // this constructor is not defined so nothing to test
- return 0;
- }
-
- T ex = cons.newInstance();
-
- assertNotNull(ex.toString());
- assertNull(ex.getMessage());
- assertNull(ex.getCause());
-
- return 1;
- }
-
- /**
- * Tests exceptions created via the constructor that takes just a String.
- * Verifies that:
- * <ul>
- * <li><i>toString()</i> returns a non-null value</li>
- * <li><i>getMessage()</i> returns the original message passed to the
- * constructor</li>
- * <li><i>getCause()</i> returns null</li>
- * </ul>
- *
- * If the Exception subclass does not support this type of constructor, then
- * this method simply returns.
- *
- * @param claz
- * subclass to be tested
- * @return {@code 1}, if the subclass supports this type of constructor,
- * {@code 0} otherwise
- * @throws Exception
- * if the Exception cannot be constructed
- */
- public <T extends Exception> int testString(Class<T> claz) throws Exception {
- Constructor<T> cons;
-
- try {
- cons = claz.getConstructor(String.class);
-
- } catch (NoSuchMethodException | SecurityException e) {
- // this constructor is not defined so nothing to test
- return 0;
- }
-
- T ex = cons.newInstance("hello");
-
- assertNotNull(ex.toString());
- assertEquals("hello", ex.getMessage());
- assertNull(ex.getCause());
-
- return 1;
- }
-
- /**
- * Tests exceptions created via the constructor that takes just a Throwable.
- * Verifies that:
- * <ul>
- * <li><i>toString()</i> returns a non-null value</li>
- * <li><i>getMessage()</i> returns the cause's message</li>
- * <li><i>getCause()</i> returns the original cause passed to the
- * constructor</li>
- * </ul>
- *
- * If the Exception subclass does not support this type of constructor, then
- * this method simply returns.
+ * Runs tests, on an Exception subclass, for all of the standard
+ * constructors. If the Exception subclass does not support a given type of
+ * constructor, then it skips that test. Does <i>not</i> throw an exception
+ * if no standard constructors are found.
*
* @param claz
* subclass to be tested
- * @return {@code 1}, if the subclass supports this type of constructor,
- * {@code 0} otherwise
- * @throws Exception
- * if the Exception cannot be constructed
+ * @return the number of constructors that were found/tested
+ * @throws ConstructionError
+ * if the Exception subclass cannot be constructed
+ * @throws AssertionError
+ * if the constructed objects fail to pass various tests
*/
- public <T extends Exception> int testThrowable(Class<T> claz) throws Exception {
- Constructor<T> cons;
-
- try {
- cons = claz.getConstructor(Throwable.class);
-
- } catch (NoSuchMethodException | SecurityException e) {
- // this constructor is not defined so nothing to test
- return 0;
- }
-
- Throwable cause = new Throwable("expected exception");
- T ex = cons.newInstance(cause);
+ public <T extends Exception> int testException(Class<T> claz) {
+ int ncons = 0;
- assertEquals(ex.getMessage(), ex.getMessage());
- assertNotNull(ex.toString());
- assertEquals(cause, ex.getCause());
+ ncons += testThrowable(claz);
+ ncons += testException_Exception(claz);
+ ncons += testException_StringException(claz);
+ ncons += testException_StringExceptionBooleanBoolean(claz);
- return 1;
+ return ncons;
}
/**
@@ -197,22 +95,19 @@ public class ExceptionsTester {
* subclass to be tested
* @return {@code 1}, if the subclass supports this type of constructor,
* {@code 0} otherwise
- * @throws Exception
- * if the Exception cannot be constructed
+ * @throws ConstructionError
+ * if the Exception subclass cannot be constructed
+ * @throws AssertionError
+ * if the constructed objects fail to pass various tests
*/
- public <T extends Exception> int testException(Class<T> claz) throws Exception {
- Constructor<T> cons;
-
- try {
- cons = claz.getConstructor(Exception.class);
-
- } catch (NoSuchMethodException | SecurityException e) {
- // this constructor is not defined so nothing to test
+ public <T extends Exception> int testException_Exception(Class<T> claz) {
+ Constructor<T> cons = getConstructor(claz, "exception", Exception.class);
+ if (cons == null) {
return 0;
}
- Exception cause = new Exception("expected exception");
- T ex = cons.newInstance(cause);
+ Exception cause = new Exception(EXPECTED_EXCEPTION_MSG);
+ T ex = newInstance(cons, cause);
assertNotNull(ex.toString());
assertEquals(ex.getMessage(), ex.getMessage());
@@ -222,48 +117,6 @@ public class ExceptionsTester {
}
/**
- * Tests exceptions created via the constructor that takes a String and a
- * Throwable. Verifies that:
- * <ul>
- * <li><i>toString()</i> returns a non-null value</li>
- * <li><i>getMessage()</i> returns the original message passed to the
- * constructor</li>
- * <li><i>getCause()</i> returns the original cause passed to the
- * constructor</li>
- * </ul>
- *
- * If the Exception subclass does not support this type of constructor, then
- * this method simply returns.
- *
- * @param claz
- * subclass to be tested
- * @return {@code 1}, if the subclass supports this type of constructor,
- * {@code 0} otherwise
- * @throws Exception
- * if the Exception cannot be constructed
- */
- public <T extends Exception> int testStringThrowable(Class<T> claz) throws Exception {
- Constructor<T> cons;
-
- try {
- cons = claz.getConstructor(String.class, Throwable.class);
-
- } catch (NoSuchMethodException | SecurityException e) {
- // this constructor is not defined so nothing to test
- return 0;
- }
-
- Throwable cause = new Throwable("expected exception");
- T ex = cons.newInstance("world", cause);
-
- assertNotNull(ex.toString());
- assertEquals("world", ex.getMessage());
- assertEquals(cause, ex.getCause());
-
- return 1;
- }
-
- /**
* Tests exceptions created via the constructor that takes a String and an
* Exception. Verifies that:
* <ul>
@@ -281,22 +134,17 @@ public class ExceptionsTester {
* subclass to be tested
* @return {@code 1}, if the subclass supports this type of constructor,
* {@code 0} otherwise
- * @throws Exception
- * if the Exception cannot be constructed
+ * @throws ConstructionError
+ * if the Exception subclass cannot be constructed
*/
- public <T extends Exception> int testStringException(Class<T> claz) throws Exception {
- Constructor<T> cons;
-
- try {
- cons = claz.getConstructor(String.class, Exception.class);
-
- } catch (NoSuchMethodException | SecurityException e) {
- // this constructor is not defined so nothing to test
+ public <T extends Exception> int testException_StringException(Class<T> claz) {
+ Constructor<T> cons = getConstructor(claz, "string-exception", String.class, Exception.class);
+ if (cons == null) {
return 0;
}
- Exception cause = new Exception("expected exception");
- T ex = cons.newInstance("world", cause);
+ Exception cause = new Exception(EXPECTED_EXCEPTION_MSG);
+ T ex = newInstance(cons, "world", cause);
assertNotNull(ex.toString());
assertEquals("world", ex.getMessage());
@@ -306,52 +154,6 @@ public class ExceptionsTester {
}
/**
- * Tests exceptions created via the constructor that takes a String, a
- * Throwable, and two booleans. Verifies that:
- * <ul>
- * <li><i>toString()</i> returns a non-null value</li>
- * <li><i>getMessage()</i> returns the original message passed to the
- * constructor</li>
- * <li><i>getCause()</i> returns the original cause passed to the
- * constructor</li>
- * <li>suppressed exceptions can be added, if enabled</li>
- * <li>the stack trace can be added, if enabled</li>
- * </ul>
- *
- * If the Exception subclass does not support this type of constructor, then
- * this method simply returns.
- *
- * @param claz
- * subclass to be tested
- * @return {@code 1}, if the subclass supports this type of constructor,
- * {@code 0} otherwise
- * @throws Exception
- * if the Exception cannot be constructed
- */
- public <T extends Exception> int testStringThrowableBooleanBoolean(Class<T> claz) throws Exception {
- Constructor<T> cons;
-
- try {
- cons = claz.getConstructor(String.class, Throwable.class, Boolean.TYPE, Boolean.TYPE);
-
- } catch (NoSuchMethodException | SecurityException e) {
- // this constructor is not defined so nothing to test
- return 0;
- }
-
- // test each combination of "message" and "cause"
- testMessageCauseCombos(cons);
-
- // test each combination of the boolean flags
- testSuppressStack(cons);
- testSuppressNoStack(cons);
- testNoSuppressStack(cons);
- testNoSuppressNoStack(cons);
-
- return 1;
- }
-
- /**
* Tests exceptions created via the constructor that takes a String, an
* Exception, and two booleans. Verifies that:
* <ul>
@@ -371,218 +173,22 @@ public class ExceptionsTester {
* subclass to be tested
* @return {@code 1}, if the subclass supports this type of constructor,
* {@code 0} otherwise
- * @throws Exception
- * if the Exception cannot be constructed
+ * @throws ConstructionError
+ * if the Exception subclass cannot be constructed
*/
- public <T extends Exception> int testStringExceptionBooleanBoolean(Class<T> claz) throws Exception {
- Constructor<T> cons;
-
- try {
- cons = claz.getConstructor(String.class, Exception.class, Boolean.TYPE, Boolean.TYPE);
-
- } catch (NoSuchMethodException | SecurityException e) {
- // this constructor is not defined so nothing to test
+ public <T extends Exception> int testException_StringExceptionBooleanBoolean(Class<T> claz) {
+ Constructor<T> cons = getConstructor(claz, "string-exception-flags", String.class, Exception.class,
+ Boolean.TYPE, Boolean.TYPE);
+ if (cons == null) {
return 0;
}
// test each combination of "message" and "cause"
- testMessageCauseCombos(cons);
+ testThrowable_MessageCauseCombos(cons);
// test each combination of the boolean flags
- testFlagCombos(cons);
+ testThrowable_FlagCombos(cons);
return 1;
}
-
- /**
- * Tests each combination of values for the "message" and the "cause" when
- * using the constructor that takes a String, a Throwable/Exception, and two
- * booleans. Verifies that expected values are returned by <i>toString()/i>,
- * <i>getMessage()</i>, and <i>getCause()</i>.
- * </ul>
- *
- * @param cons
- * constructor to be invoked
- * @throws Exception
- * if the Exception cannot be constructed
- */
- private <T extends Exception> void testMessageCauseCombos(Constructor<T> cons) throws Exception {
- T ex;
- Exception cause = new Exception("expected throwable");
-
- ex = cons.newInstance(null, null, true, true);
- assertNotNull(ex.toString());
- assertNull(ex.getMessage());
- assertNull(ex.getCause());
-
- ex = cons.newInstance("abc", null, true, true);
- assertNotNull(ex.toString());
- assertEquals("abc", ex.getMessage());
- assertNull(ex.getCause());
-
- ex = cons.newInstance(null, cause, true, true);
- assertNotNull(ex.toString());
- assertNull(ex.getMessage());
- assertEquals(cause, ex.getCause());
-
- ex = cons.newInstance("xyz", cause, true, true);
- assertNotNull(ex.toString());
- assertEquals("xyz", ex.getMessage());
- assertEquals(cause, ex.getCause());
- }
-
- /**
- * Tests each combination of values for the "message" and the "cause" when
- * using the constructor that takes a String, a Throwable/Exception, and two
- * booleans. Verifies that expected values are returned by <i>toString()/i>,
- * <i>getMessage()</i>, and <i>getCause()</i>.
- * </ul>
- *
- * @param cons
- * constructor to be invoked
- * @throws Exception
- * if the Exception cannot be constructed
- */
- public <T extends Exception> void testFlagCombos(Constructor<T> cons) throws Exception {
- testSuppressStack(cons);
- testSuppressNoStack(cons);
- testNoSuppressStack(cons);
- testNoSuppressNoStack(cons);
- }
-
- /**
- * Tests exceptions constructed with {@code enableSuppression=true} and
- * {@code writableStackTrace=true}. Verifies that:
- * <ul>
- * <li><i>toString()</i> returns a non-null value</li>
- * <li><i>getMessage()</i> returns the original message passed to the
- * constructor</li>
- * <li><i>getCause()</i> returns the original cause passed to the
- * constructor</li>
- * <li>suppressed exceptions are added</li>
- * <li>the stack trace is added</li>
- * </ul>
- *
- * @param cons
- * the exception's class constructor
- * @throws Exception
- * if the Exception cannot be constructed
- */
- public <T extends Exception> void testSuppressStack(Constructor<T> cons) throws Exception {
- Exception cause = new Exception("expected exception");
- Throwable supr = new Throwable("expected suppressed exception");
- T ex = cons.newInstance("yes,yes", cause, true, true);
-
- ex.addSuppressed(supr);
-
- assertNotNull(ex.toString());
- assertEquals("yes,yes", ex.getMessage());
- assertEquals(cause, ex.getCause());
-
- assertEquals(1, ex.getSuppressed().length);
- assertEquals(supr, ex.getSuppressed()[0]);
-
- assertTrue(ex.getStackTrace().length > 0);
- }
-
- /**
- * Tests exceptions constructed with {@code enableSuppression=true} and
- * {@code writableStackTrace=false}. Verifies that:
- * <ul>
- * <li><i>toString()</i> returns a non-null value</li>
- * <li><i>getMessage()</i> returns the original message passed to the
- * constructor</li>
- * <li><i>getCause()</i> returns the original cause passed to the
- * constructor</li>
- * <li>suppressed exceptions are added</li>
- * <li>the stack trace is <i>not</i> added</li>
- * </ul>
- *
- * @param cons
- * the exception's class constructor
- * @throws Exception
- * if the Exception cannot be constructed
- */
- public <T extends Exception> void testSuppressNoStack(Constructor<T> cons) throws Exception {
- Exception cause = new Exception("expected exception");
- Throwable supr = new Throwable("expected suppressed exception");
- T ex = cons.newInstance("yes,no", cause, true, false);
-
- ex.addSuppressed(supr);
-
- assertNotNull(ex.toString());
- assertEquals("yes,no", ex.getMessage());
- assertEquals(cause, ex.getCause());
-
- assertEquals(1, ex.getSuppressed().length);
- assertEquals(supr, ex.getSuppressed()[0]);
-
- assertEquals(0, ex.getStackTrace().length);
- }
-
- /**
- * Tests exceptions constructed with {@code enableSuppression=false} and
- * {@code writableStackTrace=true}. Verifies that:
- * <ul>
- * <li><i>toString()</i> returns a non-null value</li>
- * <li><i>getMessage()</i> returns the original message passed to the
- * constructor</li>
- * <li><i>getCause()</i> returns the original cause passed to the
- * constructor</li>
- * <li>suppressed exceptions are <i>not</i> added</li>
- * <li>the stack trace is added</li>
- * </ul>
- *
- * @param cons
- * the exception's class constructor
- * @throws Exception
- * if the Exception cannot be constructed
- */
- public <T extends Exception> void testNoSuppressStack(Constructor<T> cons) throws Exception {
- Exception cause = new Exception("expected exception");
- Throwable supr = new Throwable("expected suppressed exception");
- T ex = cons.newInstance("no,yes", cause, false, true);
-
- ex.addSuppressed(supr);
-
- assertNotNull(ex.toString());
- assertEquals("no,yes", ex.getMessage());
- assertEquals(cause, ex.getCause());
-
- assertEquals(0, ex.getSuppressed().length);
-
- assertTrue(ex.getStackTrace().length > 0);
- }
-
- /**
- * Tests exceptions constructed with {@code enableSuppression=false} and
- * {@code writableStackTrace=false}. Verifies that:
- * <ul>
- * <li><i>toString()</i> returns a non-null value</li>
- * <li><i>getMessage()</i> returns the original message passed to the
- * constructor</li>
- * <li><i>getCause()</i> returns the original cause passed to the
- * constructor</li>
- * <li>suppressed exceptions are <i>not</i> added</li>
- * <li>the stack trace is <i>not</i> added</li>
- *
- * @param cons
- * the exception's class constructor
- * @throws Exception
- * if the Exception cannot be constructed
- */
- public <T extends Exception> void testNoSuppressNoStack(Constructor<T> cons) throws Exception {
- Exception cause = new Exception("expected exception");
- Throwable supr = new Throwable("expected suppressed exception");
- T ex = cons.newInstance("no,no", cause, false, false);
-
- ex.addSuppressed(supr);
-
- assertNotNull(ex.toString());
- assertEquals("no,no", ex.getMessage());
- assertEquals(cause, ex.getCause());
-
- assertEquals(0, ex.getSuppressed().length);
- assertEquals(0, ex.getStackTrace().length);
- }
}
diff --git a/utils-test/src/main/java/org/onap/policy/common/utils/test/ThrowablesTester.java b/utils-test/src/main/java/org/onap/policy/common/utils/test/ThrowablesTester.java
new file mode 100644
index 00000000..bd8db4fc
--- /dev/null
+++ b/utils-test/src/main/java/org/onap/policy/common/utils/test/ThrowablesTester.java
@@ -0,0 +1,515 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Integrity Monitor
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Used to test various Throwable subclasses. Uses reflection to identify the
+ * constructors that the subclass supports.
+ */
+public class ThrowablesTester {
+
+ private static Logger logger = LoggerFactory.getLogger(ThrowablesTester.class);
+
+ public static final String EXPECTED_EXCEPTION_MSG = "expected exception";
+ private static final String EXPECTED_SUPPRESSED_EXCEPTION_MSG = "expected suppressed exception";
+
+ /**
+ * Passed as a "cause" to constructors.
+ */
+ public static final Exception CAUSE = new Exception(EXPECTED_EXCEPTION_MSG);
+
+ /**
+ * Passed to new objects via the <i>addSuppressed()</i> method..
+ */
+ public static final Throwable SUPPRESSED = new Throwable(EXPECTED_SUPPRESSED_EXCEPTION_MSG);
+
+ /**
+ * Runs tests, on an Throwable subclass, for all of the standard
+ * constructors. If the Throwable subclass does not support a given type of
+ * constructor, then it skips that test. Does <i>not</i> throw an exception
+ * if no standard constructors are found.
+ *
+ * @param claz
+ * subclass to be tested
+ * @return the number of constructors that were found/tested
+ * @throws ConstructionError
+ * if the Throwable subclass cannot be constructed
+ * @throws AssertionError
+ * if the constructed objects fail to pass various tests
+ */
+ public <T extends Throwable> int testThrowable(Class<T> claz) {
+ int ncons = 0;
+
+ ncons += testThrowable_Default(claz);
+ ncons += testThrowable_StringConstuctor(claz);
+ ncons += testThrowable_Throwable(claz);
+ ncons += testThrowable_StringThrowable(claz);
+ ncons += testThrowable_StringThrowableBooleanBoolean(claz);
+
+ return ncons;
+ }
+
+ /**
+ * Tests Throwable objects created via the default constructor. Verifies
+ * that:
+ * <ul>
+ * <li><i>toString()</i> returns a non-null value</li>
+ * <li><i>getMessage()</i> returns null</li>
+ * <li><i>getCause()</i> returns null</li>
+ * </ul>
+ *
+ * If the Throwable subclass does not support this type of constructor, then
+ * this method simply returns.
+ *
+ * @param claz
+ * subclass to be tested
+ * @return {@code 1}, if the subclass supports this type of constructor,
+ * {@code 0} otherwise
+ * @throws ConstructionError
+ * if the Throwable subclass cannot be constructed
+ * @throws AssertionError
+ * if the constructed objects fail to pass various tests
+ */
+ public <T extends Throwable> int testThrowable_Default(Class<T> claz) {
+ Constructor<T> cons = getConstructor(claz, "default");
+ if (cons == null) {
+ return 0;
+ }
+
+ T ex = newInstance(cons);
+
+ assertNotNull(ex.toString());
+ assertNull(ex.getMessage());
+ assertNull(ex.getCause());
+
+ return 1;
+ }
+
+ /**
+ * Tests Throwable objects created via the constructor that takes just a
+ * String. Verifies that:
+ * <ul>
+ * <li><i>toString()</i> returns a non-null value</li>
+ * <li><i>getMessage()</i> returns the original message passed to the
+ * constructor</li>
+ * <li><i>getCause()</i> returns null</li>
+ * </ul>
+ *
+ * If the Throwable subclass does not support this type of constructor, then
+ * this method simply returns.
+ *
+ * @param claz
+ * subclass to be tested
+ * @return {@code 1}, if the subclass supports this type of constructor,
+ * {@code 0} otherwise
+ * @throws ConstructionError
+ * if the Throwable subclass cannot be constructed
+ * @throws AssertionError
+ * if the constructed objects fail to pass various tests
+ */
+ public <T extends Throwable> int testThrowable_StringConstuctor(Class<T> claz) {
+ Constructor<T> cons = getConstructor(claz, "string", String.class);
+ if (cons == null) {
+ return 0;
+ }
+
+ T ex = newInstance(cons, "hello");
+
+ assertNotNull(ex.toString());
+ assertEquals("hello", ex.getMessage());
+ assertNull(ex.getCause());
+
+ return 1;
+ }
+
+ /**
+ * Tests Throwable objects created via the constructor that takes just a
+ * Throwable. Verifies that:
+ * <ul>
+ * <li><i>toString()</i> returns a non-null value</li>
+ * <li><i>getMessage()</i> returns the cause's message</li>
+ * <li><i>getCause()</i> returns the original cause passed to the
+ * constructor</li>
+ * </ul>
+ *
+ * If the Throwable subclass does not support this type of constructor, then
+ * this method simply returns.
+ *
+ * @param claz
+ * subclass to be tested
+ * @return {@code 1}, if the subclass supports this type of constructor,
+ * {@code 0} otherwise
+ * @throws ConstructionError
+ * if the Throwable subclass cannot be constructed
+ * @throws AssertionError
+ * if the constructed objects fail to pass various tests
+ */
+ public <T extends Throwable> int testThrowable_Throwable(Class<T> claz) {
+ Constructor<T> cons = getConstructor(claz, "throwable", Throwable.class);
+ if (cons == null) {
+ return 0;
+ }
+
+ T ex = newInstance(cons, CAUSE);
+
+ assertEquals(ex.getMessage(), ex.getMessage());
+ assertNotNull(ex.toString());
+ assertEquals(CAUSE, ex.getCause());
+
+ return 1;
+ }
+
+ /**
+ * Tests Throwable objects created via the constructor that takes a String
+ * and a Throwable. Verifies that:
+ * <ul>
+ * <li><i>toString()</i> returns a non-null value</li>
+ * <li><i>getMessage()</i> returns the original message passed to the
+ * constructor</li>
+ * <li><i>getCause()</i> returns the original cause passed to the
+ * constructor</li>
+ * </ul>
+ *
+ * If the Throwable subclass does not support this type of constructor, then
+ * this method simply returns.
+ *
+ * @param claz
+ * subclass to be tested
+ * @return {@code 1}, if the subclass supports this type of constructor,
+ * {@code 0} otherwise
+ * @throws ConstructionError
+ * if the Throwable subclass cannot be constructed
+ * @throws AssertionError
+ * if the constructed objects fail to pass various tests
+ */
+ public <T extends Throwable> int testThrowable_StringThrowable(Class<T> claz) {
+ Constructor<T> cons = getConstructor(claz, "string-throwable", String.class, Throwable.class);
+ if (cons == null) {
+ return 0;
+ }
+
+ T ex = newInstance(cons, "world", CAUSE);
+
+ assertNotNull(ex.toString());
+ assertEquals("world", ex.getMessage());
+ assertEquals(CAUSE, ex.getCause());
+
+ return 1;
+ }
+
+ /**
+ * Tests Throwable objects created via the constructor that takes a String,
+ * a Throwable, and two booleans. Verifies that:
+ * <ul>
+ * <li><i>toString()</i> returns a non-null value</li>
+ * <li><i>getMessage()</i> returns the original message passed to the
+ * constructor</li>
+ * <li><i>getCause()</i> returns the original cause passed to the
+ * constructor</li>
+ * <li>suppressed exceptions can be added, if enabled</li>
+ * <li>the stack trace can be added, if enabled</li>
+ * </ul>
+ *
+ * If the Throwable subclass does not support this type of constructor, then
+ * this method simply returns.
+ *
+ * @param claz
+ * subclass to be tested
+ * @return {@code 1}, if the subclass supports this type of constructor,
+ * {@code 0} otherwise
+ * @throws ConstructionError
+ * if the Throwable subclass cannot be constructed
+ * @throws AssertionError
+ * if the constructed objects fail to pass various tests
+ */
+ public <T extends Throwable> int testThrowable_StringThrowableBooleanBoolean(Class<T> claz) {
+ Constructor<T> cons = getConstructor(claz, "string-throwable-flags", String.class, Throwable.class,
+ Boolean.TYPE, Boolean.TYPE);
+ if (cons == null) {
+ return 0;
+ }
+
+ // test each combination of "message" and "cause"
+ testThrowable_MessageCauseCombos(cons);
+
+ // test each combination of the boolean flags
+ testThrowable_SuppressStack(cons);
+ testThrowable_SuppressNoStack(cons);
+ testThrowable_NoSuppressStack(cons);
+ testThrowable_NoSuppressNoStack(cons);
+
+ return 1;
+ }
+
+ /**
+ * Tests each combination of values for the "message" and the "cause" when
+ * using the constructor that takes a String, a Throwable/Exception, and two
+ * booleans. Verifies that expected values are returned by <i>toString()/i>,
+ * <i>getMessage()</i>, and <i>getCause()</i>.
+ * </ul>
+ *
+ * @param cons
+ * constructor to be invoked
+ * @throws ConstructionError
+ * if the Throwable subclass cannot be constructed
+ * @throws AssertionError
+ * if the constructed objects fail to pass various tests
+ */
+ public <T extends Throwable> void testThrowable_MessageCauseCombos(Constructor<T> cons) {
+ T ex;
+
+ ex = newInstance(cons, null, null, true, true);
+ assertNotNull(ex.toString());
+ assertNull(ex.getMessage());
+ assertNull(ex.getCause());
+
+ ex = newInstance(cons, "abc", null, true, true);
+ assertNotNull(ex.toString());
+ assertEquals("abc", ex.getMessage());
+ assertNull(ex.getCause());
+
+ ex = newInstance(cons, null, CAUSE, true, true);
+ assertNotNull(ex.toString());
+ assertNull(ex.getMessage());
+ assertEquals(CAUSE, ex.getCause());
+
+ ex = newInstance(cons, "xyz", CAUSE, true, true);
+ assertNotNull(ex.toString());
+ assertEquals("xyz", ex.getMessage());
+ assertEquals(CAUSE, ex.getCause());
+ }
+
+ /**
+ * Tests each combination of values for the "message" and the "cause" when
+ * using the constructor that takes a String, a Throwable/Exception, and two
+ * booleans. Verifies that expected values are returned by <i>toString()/i>,
+ * <i>getMessage()</i>, and <i>getCause()</i>.
+ * </ul>
+ *
+ * @param cons
+ * constructor to be invoked
+ * @throws ConstructionError
+ * if the Throwable subclass cannot be constructed
+ * @throws AssertionError
+ * if the constructed objects fail to pass various tests
+ */
+ public <T extends Throwable> void testThrowable_FlagCombos(Constructor<T> cons) {
+ testThrowable_SuppressStack(cons);
+ testThrowable_SuppressNoStack(cons);
+ testThrowable_NoSuppressStack(cons);
+ testThrowable_NoSuppressNoStack(cons);
+ }
+
+ /**
+ * Tests Throwable objects constructed with {@code enableSuppression=true}
+ * and {@code writableStackTrace=true}. Verifies that:
+ * <ul>
+ * <li><i>toString()</i> returns a non-null value</li>
+ * <li><i>getMessage()</i> returns the original message passed to the
+ * constructor</li>
+ * <li><i>getCause()</i> returns the original cause passed to the
+ * constructor</li>
+ * <li>suppressed exceptions are added</li>
+ * <li>the stack trace is added</li>
+ * </ul>
+ *
+ * @param cons
+ * the throwable's class constructor
+ * @throws ConstructionError
+ * if the Throwable subclass cannot be constructed
+ * @throws AssertionError
+ * if the constructed objects fail to pass various tests
+ */
+ public <T extends Throwable> void testThrowable_SuppressStack(Constructor<T> cons) {
+ T ex = newInstance(cons, "yes,yes", CAUSE, true, true);
+
+ ex.addSuppressed(SUPPRESSED);
+
+ assertNotNull(ex.toString());
+ assertEquals("yes,yes", ex.getMessage());
+ assertEquals(CAUSE, ex.getCause());
+
+ assertEquals(1, ex.getSuppressed().length);
+ assertEquals(SUPPRESSED, ex.getSuppressed()[0]);
+
+ assertTrue(ex.getStackTrace().length > 0);
+ }
+
+ /**
+ * Tests Throwable objects constructed with {@code enableSuppression=true}
+ * and {@code writableStackTrace=false}. Verifies that:
+ * <ul>
+ * <li><i>toString()</i> returns a non-null value</li>
+ * <li><i>getMessage()</i> returns the original message passed to the
+ * constructor</li>
+ * <li><i>getCause()</i> returns the original cause passed to the
+ * constructor</li>
+ * <li>suppressed exceptions are added</li>
+ * <li>the stack trace is <i>not</i> added</li>
+ * </ul>
+ *
+ * @param cons
+ * the throwable's class constructor
+ * @throws ConstructionError
+ * if the Throwable subclass cannot be constructed
+ * @throws AssertionError
+ * if the constructed objects fail to pass various tests
+ */
+ public <T extends Throwable> void testThrowable_SuppressNoStack(Constructor<T> cons) {
+ T ex = newInstance(cons, "yes,no", CAUSE, true, false);
+
+ ex.addSuppressed(SUPPRESSED);
+
+ assertNotNull(ex.toString());
+ assertEquals("yes,no", ex.getMessage());
+ assertEquals(CAUSE, ex.getCause());
+
+ assertEquals(1, ex.getSuppressed().length);
+ assertEquals(SUPPRESSED, ex.getSuppressed()[0]);
+
+ assertEquals(0, ex.getStackTrace().length);
+ }
+
+ /**
+ * Tests Throwable objects constructed with {@code enableSuppression=false}
+ * and {@code writableStackTrace=true}. Verifies that:
+ * <ul>
+ * <li><i>toString()</i> returns a non-null value</li>
+ * <li><i>getMessage()</i> returns the original message passed to the
+ * constructor</li>
+ * <li><i>getCause()</i> returns the original cause passed to the
+ * constructor</li>
+ * <li>suppressed exceptions are <i>not</i> added</li>
+ * <li>the stack trace is added</li>
+ * </ul>
+ *
+ * @param cons
+ * the throwable's class constructor
+ * @throws ConstructionError
+ * if the Throwable subclass cannot be constructed
+ * @throws AssertionError
+ * if the constructed objects fail to pass various tests
+ */
+ public <T extends Throwable> void testThrowable_NoSuppressStack(Constructor<T> cons) {
+ T ex = newInstance(cons, "no,yes", CAUSE, false, true);
+
+ ex.addSuppressed(SUPPRESSED);
+
+ assertNotNull(ex.toString());
+ assertEquals("no,yes", ex.getMessage());
+ assertEquals(CAUSE, ex.getCause());
+
+ assertEquals(0, ex.getSuppressed().length);
+
+ assertTrue(ex.getStackTrace().length > 0);
+ }
+
+ /**
+ * Tests Throwable objects constructed with {@code enableSuppression=false}
+ * and {@code writableStackTrace=false}. Verifies that:
+ * <ul>
+ * <li><i>toString()</i> returns a non-null value</li>
+ * <li><i>getMessage()</i> returns the original message passed to the
+ * constructor</li>
+ * <li><i>getCause()</i> returns the original cause passed to the
+ * constructor</li>
+ * <li>suppressed exceptions are <i>not</i> added</li>
+ * <li>the stack trace is <i>not</i> added</li>
+ *
+ * @param cons
+ * the throwable's class constructor
+ * @throws ConstructionError
+ * if the Throwable subclass cannot be constructed
+ * @throws AssertionError
+ * if the constructed objects fail to pass various tests
+ */
+ public <T extends Throwable> void testThrowable_NoSuppressNoStack(Constructor<T> cons) {
+ T ex = newInstance(cons, "no,no", CAUSE, false, false);
+
+ ex.addSuppressed(SUPPRESSED);
+
+ assertNotNull(ex.toString());
+ assertEquals("no,no", ex.getMessage());
+ assertEquals(CAUSE, ex.getCause());
+
+ assertEquals(0, ex.getSuppressed().length);
+ assertEquals(0, ex.getStackTrace().length);
+ }
+
+ /**
+ * Attempts to get a constructor for objects of a given type.
+ *
+ * @param claz
+ * class of objects whose constructor is to be gotten
+ * @param testType
+ * type of test being run
+ * @param argTypes
+ * argument types to be passed to the constructor
+ * @return the desired constructor, or {@code null} if the desired
+ * constructor is not available
+ */
+ protected <T extends Throwable> Constructor<T> getConstructor(Class<T> claz, String testType,
+ Class<?>... argTypes) {
+
+ try {
+ return claz.getConstructor(argTypes);
+
+ } catch (NoSuchMethodException | SecurityException e) {
+ // this constructor is not defined so nothing to test
+ logger.debug("skipped test due to no " + testType + " constructor for: " + claz);
+ return null;
+ }
+ }
+
+ /**
+ * Creates a new instance of an Throwable subclass.
+ *
+ * @param cons
+ * subclass constructor
+ * @param args
+ * arguments to be passed to the constructor
+ * @return a new instance of the Throwable subclass
+ * @throws ConstructionError
+ * if the Throwable subclass cannot be constructed
+ */
+ protected <T extends Throwable> T newInstance(Constructor<T> cons, Object... args) {
+ try {
+ return cons.newInstance(args);
+
+ } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
+ | InvocationTargetException e) {
+
+ throw new ConstructionError(e);
+ }
+
+ }
+}
diff --git a/utils-test/src/main/java/org/onap/policy/common/utils/test/log/logback/ExtractAppender.java b/utils-test/src/main/java/org/onap/policy/common/utils/test/log/logback/ExtractAppender.java
new file mode 100644
index 00000000..f012464c
--- /dev/null
+++ b/utils-test/src/main/java/org/onap/policy/common/utils/test/log/logback/ExtractAppender.java
@@ -0,0 +1,191 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Integrity Audit
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.test.log.logback;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import ch.qos.logback.classic.spi.ILoggingEvent;
+import ch.qos.logback.core.AppenderBase;
+
+/**
+ * This is an appender that is intended for use by JUnit tests that wish to
+ * capture logged messages. The appender takes an optional list of regular
+ * expressions that are used to identify and extract data of interest.
+ * <p/>
+ * If no patterns are provided, then every logged message is recorded. However,
+ * if patterns are provided, then only messages that match one of the patterns
+ * are recorded. In addition, if the pattern contains a capture group that is
+ * non-null, only the captured group is recorded. Otherwise, the entire portion
+ * of the message that matches the pattern is recorded.
+ * <p/>
+ * All operations are thread-safe.
+ */
+public class ExtractAppender extends AppenderBase<ILoggingEvent> {
+
+ /**
+ * Extracted text is placed here.
+ */
+ private final Queue<String> extracted;
+
+ /**
+ * Regular expressions/Patterns to be used to extract text. Uses a
+ * LinkedHashMap so that order is preserved.
+ */
+ private final LinkedHashMap<String, Pattern> patterns;
+
+ /**
+ * Records every message that is logged.
+ */
+ public ExtractAppender() {
+ this(new LinkedList<>());
+ }
+
+ /**
+ * Records portions of messages that match one of the regular expressions.
+ *
+ * @param regex
+ * regular expression (i.e., {@link Pattern}) to match
+ */
+ public ExtractAppender(String... regex) {
+ this(new LinkedList<>(), regex);
+ }
+
+ /**
+ * Rather than allocating an internal queue to store matched messages,
+ * messages are recorded in the specified target queue using the
+ * {@link Queue#offer(Object)} method. Note: whenever the queue is used, it
+ * will be synchronized to prevent simultaneous accesses.
+ *
+ * @param target
+ * @param regex
+ * regular expression (i.e., {@link Pattern}) to match
+ */
+ public ExtractAppender(Queue<String> target, String... regex) {
+ extracted = target;
+ patterns = new LinkedHashMap<>(regex.length);
+
+ for (String re : regex) {
+ patterns.put(re, Pattern.compile(re));
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see ch.qos.logback.core.AppenderBase#append(Object)
+ */
+ @Override
+ protected void append(ILoggingEvent event) {
+
+ String msg = event.getMessage();
+
+ synchronized (patterns) {
+ if (patterns.isEmpty()) {
+ addExtraction(msg);
+ return;
+ }
+
+ for (Pattern p : patterns.values()) {
+ Matcher m = p.matcher(msg);
+
+ if (m.find()) {
+ addGroupMatch(m);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds the first match group to {@link #extracted}.
+ *
+ * @param mat
+ * the matcher containing the groups
+ * @return {@code true} if a group was found, {@code false} otherwise
+ */
+ private void addGroupMatch(Matcher mat) {
+ int ngroups = mat.groupCount();
+
+ for (int x = 1; x <= ngroups; ++x) {
+ String txt = mat.group(x);
+
+ if (txt != null) {
+ addExtraction(txt);
+ return;
+ }
+ }
+
+ addExtraction(mat.group());
+ }
+
+ /**
+ * Adds an item to {@link #extracted}, in a thread-safe manner. It uses the
+ * queue's <i>offer()</i> method so that the queue can discard the item if
+ * it so chooses, without generating an exception.
+ *
+ * @param txt
+ * text to be added
+ */
+ private void addExtraction(String txt) {
+ synchronized (extracted) {
+ extracted.offer(txt);
+ }
+ }
+
+ /**
+ * Gets the text that has been extracted.
+ *
+ * @return a copy of the text that has been extracted
+ */
+ public List<String> getExtracted() {
+ synchronized (extracted) {
+ return new ArrayList<>(extracted);
+ }
+ }
+
+ /**
+ * Clears the list of extracted text.
+ */
+ public void clearExtractions() {
+ synchronized (extracted) {
+ extracted.clear();
+ }
+ }
+
+ /**
+ * Adds a pattern to be matched by this appender.
+ *
+ * @param regex
+ * regular expression (i.e., {@link Pattern}) to match
+ */
+ public void setPattern(String regex) {
+ synchronized (patterns) {
+ patterns.put(regex, Pattern.compile(regex));
+ }
+ }
+
+}
diff --git a/utils-test/src/test/java/org/onap/policy/common/utils/test/ConstructionErrorTest.java b/utils-test/src/test/java/org/onap/policy/common/utils/test/ConstructionErrorTest.java
new file mode 100644
index 00000000..4a6cd90e
--- /dev/null
+++ b/utils-test/src/test/java/org/onap/policy/common/utils/test/ConstructionErrorTest.java
@@ -0,0 +1,37 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Integrity Audit
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.test;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+
+/**
+ *
+ */
+public class ConstructionErrorTest extends ErrorsTester {
+
+ @Test
+ public void test() throws Exception {
+ assertEquals(4, testError(ConstructionError.class));
+ }
+
+}
diff --git a/utils-test/src/test/java/org/onap/policy/common/utils/test/ErrorsTesterTest.java b/utils-test/src/test/java/org/onap/policy/common/utils/test/ErrorsTesterTest.java
new file mode 100644
index 00000000..ae684d52
--- /dev/null
+++ b/utils-test/src/test/java/org/onap/policy/common/utils/test/ErrorsTesterTest.java
@@ -0,0 +1,77 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Integrity Monitor
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.test;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class ErrorsTesterTest {
+
+ @Test
+ public void test() {
+ assertEquals(2, new ErrorsTester().testError(SimpleError.class));
+ assertEquals(5, new ErrorsTester().testError(StaticError.class));
+ }
+
+ /**
+ * Used to test a simple success case.
+ */
+ public static class SimpleError extends Error {
+ private static final long serialVersionUID = 1L;
+
+ public SimpleError() {
+ super();
+ }
+
+ public SimpleError(String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * Used to test the exhaustive success case.
+ */
+ public static class StaticError extends Error {
+ private static final long serialVersionUID = 1L;
+
+ public StaticError() {
+ super();
+ }
+
+ public StaticError(String message) {
+ super(message);
+ }
+
+ public StaticError(Throwable cause) {
+ super(cause);
+ }
+
+ public StaticError(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public StaticError(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+ }
+
+}
diff --git a/utils-test/src/test/java/org/onap/policy/common/utils/test/ExceptionsTesterTest.java b/utils-test/src/test/java/org/onap/policy/common/utils/test/ExceptionsTesterTest.java
index c6af77a2..3848acd0 100644
--- a/utils-test/src/test/java/org/onap/policy/common/utils/test/ExceptionsTesterTest.java
+++ b/utils-test/src/test/java/org/onap/policy/common/utils/test/ExceptionsTesterTest.java
@@ -27,124 +27,26 @@ import org.junit.Test;
public class ExceptionsTesterTest {
@Test
- public void test() throws Exception {
+ public void test() {
assertEquals(2, new ExceptionsTester().test(SimpleException.class));
assertEquals(8, new ExceptionsTester().test(StaticException.class));
}
@Test(expected = AssertionError.class)
- public void testIgnoreMessageException() throws Exception {
- new ExceptionsTester().test(IgnoreMessageException.class);
- }
-
- @Test(expected = AssertionError.class)
- public void testIgnoreCauseException() throws Exception {
- new ExceptionsTester().test(IgnoreCauseException.class);
- }
-
- @Test(expected = AssertionError.class)
- public void testNonStaticException() throws Exception {
+ public void testNoConstructorsException() {
new ExceptionsTester().test(NoConstructorsException.class);
}
- @Test(expected = AssertionError.class)
- public void testAlwaysSuppressException() throws Exception {
- new ExceptionsTester().test(AlwaysSuppressException.class);
- }
-
- @Test(expected = AssertionError.class)
- public void testNeverSuppressException() throws Exception {
- new ExceptionsTester().test(NeverSuppressException.class);
- }
-
- @Test(expected = AssertionError.class)
- public void testAlwaysWritableException() throws Exception {
- new ExceptionsTester().test(AlwaysWritableException.class);
- }
-
- @Test(expected = AssertionError.class)
- public void testNeverWritableException() throws Exception {
- new ExceptionsTester().test(NeverWritableException.class);
- }
-
/**
- * Used to test a failure case - message text is ignored.
- */
- public static class IgnoreMessageException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public IgnoreMessageException(String message) {
- super("bogus");
- }
- }
-
- /**
- * Used to test a failure case - cause is ignored.
- */
- public static class IgnoreCauseException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public IgnoreCauseException(Throwable cause) {
- super(new Exception("another cause"));
- }
- }
-
- /**
- * Used to test a failure case - this has no standard constructions.
+ * Used to test a failure case - this has no standard constructors. The only
+ * constructor it has takes an "int", thus it is not one of the standard
+ * constructors.
*/
public static class NoConstructorsException extends Exception {
private static final long serialVersionUID = 1L;
public NoConstructorsException(int value) {
- super(String.valueOf(value));
- }
- }
-
- /**
- * Used to test a failure case - always suppresses.
- */
- public static class AlwaysSuppressException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public AlwaysSuppressException(String message, Throwable cause, boolean enableSuppression,
- boolean writableStackTrace) {
- super(message, cause, true, writableStackTrace);
- }
- }
-
- /**
- * Used to test a failure case - never suppresses.
- */
- public static class NeverSuppressException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public NeverSuppressException(String message, Throwable cause, boolean enableSuppression,
- boolean writableStackTrace) {
- super(message, cause, false, writableStackTrace);
- }
- }
-
- /**
- * Used to test a failure case - always allows stack writes.
- */
- public static class AlwaysWritableException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public AlwaysWritableException(String message, Throwable cause, boolean enableSuppression,
- boolean writableStackTrace) {
- super(message, cause, enableSuppression, true);
- }
- }
-
- /**
- * Used to test a failure case - never allows stack writes.
- */
- public static class NeverWritableException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public NeverWritableException(String message, Throwable cause, boolean enableSuppression,
- boolean writableStackTrace) {
- super(message, cause, enableSuppression, false);
+ super();
}
}
diff --git a/utils-test/src/test/java/org/onap/policy/common/utils/test/ThrowablesTesterTest.java b/utils-test/src/test/java/org/onap/policy/common/utils/test/ThrowablesTesterTest.java
new file mode 100644
index 00000000..cb96e98f
--- /dev/null
+++ b/utils-test/src/test/java/org/onap/policy/common/utils/test/ThrowablesTesterTest.java
@@ -0,0 +1,216 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Integrity Monitor
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.test;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class ThrowablesTesterTest {
+
+ @Test
+ public void test() {
+ assertEquals(2, new ThrowablesTester().testThrowable(SimpleThrowable.class));
+ assertEquals(5, new ThrowablesTester().testThrowable(StaticThrowable.class));
+ }
+
+ @Test
+ public void testNoConstructorsThrowable() {
+ // this will not throw an error, but it should return 0, as there are
+ // no matching constructors
+ assertEquals(0, new ThrowablesTester().testThrowable(NoConstructorsThrowable.class));
+ }
+
+ @Test(expected = AssertionError.class)
+ public void testIgnoreMessageThrowable() {
+ new ThrowablesTester().testThrowable(IgnoreMessageThrowable.class);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void testIgnoreCauseThrowable() {
+ new ThrowablesTester().testThrowable(IgnoreCauseThrowable.class);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void testAlwaysSuppressThrowable() {
+ new ThrowablesTester().testThrowable(AlwaysSuppressThrowable.class);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void testNeverSuppressThrowable() {
+ new ThrowablesTester().testThrowable(NeverSuppressThrowable.class);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void testAlwaysWritableThrowable() {
+ new ThrowablesTester().testThrowable(AlwaysWritableThrowable.class);
+ }
+
+ @Test(expected = AssertionError.class)
+ public void testNeverWritableThrowable() {
+ new ThrowablesTester().testThrowable(NeverWritableThrowable.class);
+ }
+
+ @Test(expected = ConstructionError.class)
+ public void testThrowInstantiationException() {
+ new ThrowablesTester().testThrowable(ThrowInstantiationException.class);
+ }
+
+ /**
+ * Used to test a failure case - message text is ignored.
+ */
+ public static class IgnoreMessageThrowable extends Throwable {
+ private static final long serialVersionUID = 1L;
+
+ public IgnoreMessageThrowable(String message) {
+ super("bogus");
+ }
+ }
+
+ /**
+ * Used to test a failure case - cause is ignored.
+ */
+ public static class IgnoreCauseThrowable extends Throwable {
+ private static final long serialVersionUID = 1L;
+
+ public IgnoreCauseThrowable(Throwable cause) {
+ super(new Throwable("another cause"));
+ }
+ }
+
+ /**
+ * Used to test a failure case - this has no standard constructors. The only
+ * constructor it has takes an "int", thus it is not one of the standard
+ * constructors.
+ */
+ public static class NoConstructorsThrowable extends Throwable {
+ private static final long serialVersionUID = 1L;
+
+ public NoConstructorsThrowable(int value) {
+ super();
+ }
+ }
+
+ /**
+ * Used to test a failure case - always suppresses.
+ */
+ public static class AlwaysSuppressThrowable extends Throwable {
+ private static final long serialVersionUID = 1L;
+
+ public AlwaysSuppressThrowable(String message, Throwable cause, boolean enableSuppression,
+ boolean writableStackTrace) {
+ super(message, cause, true, writableStackTrace);
+ }
+ }
+
+ /**
+ * Used to test a failure case - never suppresses.
+ */
+ public static class NeverSuppressThrowable extends Throwable {
+ private static final long serialVersionUID = 1L;
+
+ public NeverSuppressThrowable(String message, Throwable cause, boolean enableSuppression,
+ boolean writableStackTrace) {
+ super(message, cause, false, writableStackTrace);
+ }
+ }
+
+ /**
+ * Used to test a failure case - always allows stack writes.
+ */
+ public static class AlwaysWritableThrowable extends Throwable {
+ private static final long serialVersionUID = 1L;
+
+ public AlwaysWritableThrowable(String message, Throwable cause, boolean enableSuppression,
+ boolean writableStackTrace) {
+ super(message, cause, enableSuppression, true);
+ }
+ }
+
+ /**
+ * Used to test a failure case - never allows stack writes.
+ */
+ public static class NeverWritableThrowable extends Throwable {
+ private static final long serialVersionUID = 1L;
+
+ public NeverWritableThrowable(String message, Throwable cause, boolean enableSuppression,
+ boolean writableStackTrace) {
+ super(message, cause, enableSuppression, false);
+ }
+ }
+
+ /**
+ * Used to test a failure case - throws InstantiationException when
+ * constructed.
+ */
+ public static class ThrowInstantiationException extends Throwable {
+ private static final long serialVersionUID = 1L;
+
+ public ThrowInstantiationException(String message, Throwable cause, boolean enableSuppression,
+ boolean writableStackTrace) throws InstantiationException {
+
+ throw new InstantiationException(ThrowablesTester.EXPECTED_EXCEPTION_MSG);
+ }
+ }
+
+ /**
+ * Used to test a simple success case.
+ */
+ public static class SimpleThrowable extends Throwable {
+ private static final long serialVersionUID = 1L;
+
+ public SimpleThrowable() {
+ super();
+ }
+
+ public SimpleThrowable(String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * Used to test the exhaustive success case.
+ */
+ public static class StaticThrowable extends Throwable {
+ private static final long serialVersionUID = 1L;
+
+ public StaticThrowable() {
+ super();
+ }
+
+ public StaticThrowable(String message) {
+ super(message);
+ }
+
+ public StaticThrowable(Throwable cause) {
+ super(cause);
+ }
+
+ public StaticThrowable(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public StaticThrowable(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+ }
+
+}
diff --git a/utils-test/src/test/java/org/onap/policy/common/utils/test/log/logback/ExtractAppenderTest.java b/utils-test/src/test/java/org/onap/policy/common/utils/test/log/logback/ExtractAppenderTest.java
new file mode 100644
index 00000000..a9a69252
--- /dev/null
+++ b/utils-test/src/test/java/org/onap/policy/common/utils/test/log/logback/ExtractAppenderTest.java
@@ -0,0 +1,484 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Integrity Audit
+ * ================================================================================
+ * Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.common.utils.test.log.logback;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.slf4j.LoggerFactory;
+
+import ch.qos.logback.classic.Level;
+import ch.qos.logback.classic.Logger;
+import ch.qos.logback.classic.spi.ILoggingEvent;
+
+public class ExtractAppenderTest {
+
+ /**
+ * Milliseconds to wait for a thread to terminate.
+ */
+ private static final long THREAD_WAIT_MS = 5000l;
+
+ private static Logger logger;
+
+ private List<Thread> threads;
+
+ @BeforeClass
+ public static void setUpBeforeClass() throws Exception {
+ logger = (Logger) LoggerFactory.getLogger(ExtractAppenderTest.class);
+ logger.setLevel(Level.INFO);
+ }
+
+ @Before
+ public void setUp() throws Exception {
+ threads = new LinkedList<>();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ logger.detachAndStopAllAppenders();
+
+ for (Thread p : threads) {
+ p.interrupt();
+ p.join(THREAD_WAIT_MS);
+ }
+ }
+
+ @Test
+ public void testExtractAppender() {
+ AtomicInteger count = new AtomicInteger(0);
+
+ ExtractAppender p = new ExtractAppender() {
+ @Override
+ protected void append(ILoggingEvent event) {
+ count.incrementAndGet();
+ super.append(event);
+ }
+ };
+
+ addAppender(p);
+
+ logger.info("hello");
+ logger.info("world");
+
+ // "append" should always be called
+ assertEquals(2, count.get());
+
+ // appender with no patterns - everything should match
+ assertEquals(strList("hello", "world"), p.getExtracted());
+
+ // add a pattern and verify match
+ p.setPattern("abc[0-9]");
+ logger.info("hello abc1");
+
+ // this should not match
+ logger.info("hello def2");
+
+ assertEquals(4, count.get());
+ assertEquals(strList("hello", "world", "abc1"), p.getExtracted());
+ }
+
+ @Test
+ public void testExtractAppenderStringArray() {
+ AtomicInteger count = new AtomicInteger(0);
+
+ ExtractAppender p = new ExtractAppender("abc[0-9]", "def[0-9]") {
+ @Override
+ protected void append(ILoggingEvent event) {
+ count.incrementAndGet();
+ super.append(event);
+ }
+ };
+
+ addAppender(p);
+
+ logger.info("hello abc1 world");
+ logger.info("world ghi2 world"); // no match
+ logger.info("world def3 world");
+ logger.info("hello abc4");
+ logger.info("abc5 world");
+ logger.info("hello def6");
+ logger.info("ghi7 world"); // no match
+ logger.info("def8 world");
+
+ // "append" should always be called
+ assertEquals(8, count.get());
+
+ assertEquals(strList("abc1", "def3", "abc4", "abc5", "def6", "def8"), p.getExtracted());
+
+ p.setPattern("ghi[0-9]");
+ logger.info("hello abc9");
+ logger.info("hello ghi9");
+
+ // this should not match
+ logger.info("hello xyz");
+
+ assertEquals(11, count.get());
+ assertEquals(strList("abc1", "def3", "abc4", "abc5", "def6", "def8", "abc9", "ghi9"), p.getExtracted());
+ }
+
+ @Test
+ public void testExtractAppenderQueueStringArray() {
+ // no. of matches allowed in the list
+ int nallowed = 3;
+
+ AtomicInteger count = new AtomicInteger(0);
+
+ LinkedList<String> queue = new LinkedList<String>() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public boolean offer(String e) {
+ if(count.incrementAndGet() <= nallowed) {
+ return super.offer(e);
+
+ } else {
+ return false;
+ }
+ }
+ };
+
+ ExtractAppender p = new ExtractAppender(queue, "abc[0-9]");
+ addAppender(p);
+
+ // these shouldn't match
+ for(int x = 0; x < 10; ++x) {
+ logger.info("xyz");
+ }
+
+ int nmatches = 10;
+
+ LinkedList<String> expected = new LinkedList<>();
+
+ for(int x = 0; x < nmatches; ++x) {
+ String msg = "abc" + x;
+ logger.info(msg + " world");
+
+ if(x < nallowed) {
+ expected.add(msg);
+ }
+ }
+
+ // "offer" should always be called for a match
+ assertEquals(nmatches, count.get());
+
+ assertEquals(expected, p.getExtracted());
+ }
+
+ @Test
+ public void testAppendILoggingEvent_NoPatterns() {
+ ExtractAppender p = makeAppender();
+
+ logger.info("hello");
+ logger.info("world");
+
+ assertEquals(strList("hello", "world"), p.getExtracted());
+ }
+
+ @Test
+ public void testAppendILoggingEvent_MatchFirstPattern() {
+ ExtractAppender p = makeAppender("abc[0-9]", "def[0-9]");
+
+ logger.info("hello abc1");
+ logger.info("world xyz2");
+
+ assertEquals(strList("abc1"), p.getExtracted());
+ }
+
+ @Test
+ public void testAppendILoggingEvent_MatchLastPattern() {
+ ExtractAppender p = makeAppender("abc[0-9]", "def[0-9]");
+
+ logger.info("hello def1");
+ logger.info("world xyz2");
+
+ assertEquals(strList("def1"), p.getExtracted());
+ }
+
+ @Test
+ public void testAppendILoggingEvent_Group1() {
+ ExtractAppender p = makeAppender("hello (abc)|(xyz)", "def[0-9]");
+
+ logger.info("hello abc, world!");
+ logger.info("world abc");
+
+ assertEquals(strList("abc"), p.getExtracted());
+ }
+
+ @Test
+ public void testAppendILoggingEvent_Group3() {
+ ExtractAppender p = makeAppender("hello (abc)|(pdq)|(xyz)", "def[0-9]");
+
+ logger.info("say hello xyz, world!");
+ logger.info("world abc");
+
+ assertEquals(strList("xyz"), p.getExtracted());
+ }
+
+ @Test
+ public void testAppendILoggingEvent_NoGroup() {
+ ExtractAppender p = makeAppender("hello abc");
+
+ logger.info("say hello abc, world!");
+ logger.info("world abc");
+
+ assertEquals(strList("hello abc"), p.getExtracted());
+ }
+
+ @Test
+ public void testGetExtracted() {
+ ExtractAppender p = makeAppender("abc[1-9]");
+
+ logger.info("hello abc1 world");
+ logger.info("world ghi2 world"); // no match
+ logger.info("hello abc3");
+
+ List<String> oldlst = p.getExtracted();
+ assertEquals(strList("abc1", "abc3"), oldlst);
+ assertEquals(oldlst, p.getExtracted());
+
+ logger.info("abc9");
+ assertEquals(strList("abc1", "abc3", "abc9"), p.getExtracted());
+ }
+
+ @Test
+ public void testClearExtractions() {
+ ExtractAppender p = makeAppender("abc[1-9]");
+
+ logger.info("hello abc1 world");
+ logger.info("world ghi2 world");
+ logger.info("hello abc3");
+
+ assertEquals(strList("abc1", "abc3"), p.getExtracted());
+
+ p.clearExtractions();
+
+ // list should be empty now
+ assertEquals(strList(), p.getExtracted());
+
+ logger.info("hello abc4 world");
+ logger.info("world ghi5 world");
+ logger.info("hello abc6");
+
+ // list should only contain the new items
+ assertEquals(strList("abc4", "abc6"), p.getExtracted());
+ }
+
+ @Test
+ public void testSetPattern() {
+ ExtractAppender p = makeAppender("abc[1-9]");
+
+ logger.info("hello abc1 world");
+ logger.info("world ghi2 world"); // no match
+ logger.info("hello abc3");
+
+ assertEquals(strList("abc1", "abc3"), p.getExtracted());
+
+ p.setPattern("ghi[0-9]");
+
+ logger.info("world ghi4 world"); // this should match now
+ logger.info("hello abc5"); // this should still match
+ logger.info("hello xyz5"); // no match
+
+ assertEquals(strList("abc1", "abc3", "ghi4", "abc5"), p.getExtracted());
+ }
+
+ /**
+ * Launches threads doing everything in parallel to ensure nothing crashes.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void test_MultiThreaded() throws Exception {
+ // when to stop
+ long tend = System.currentTimeMillis() + 250;
+
+ // maximum number of items allowed in the extraction list
+ int maxItems = 10;
+
+ // this will be set if one of the threads generates an error
+ AtomicBoolean err = new AtomicBoolean(false);
+
+ // extracted messages go here - this is a finite-length queue since
+ // we don't know how many messages may actually be logged
+ LinkedList<String> queue = new LinkedList<String>() {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public boolean offer(String e) {
+ if (size() < maxItems) {
+ return super.offer(e);
+ } else {
+ return false;
+ }
+ }
+ };
+
+ ExtractAppender app = new ExtractAppender(queue, "abc[1-9]");
+ addAppender(app);
+
+ // create some threads to add another pattern
+ addThread(tend, err, xtxt -> {
+ app.setPattern("def[0-9]");
+ });
+
+ // create some threads to log "abc" messages
+ addThread(tend, err, xtxt -> {
+ logger.info("hello abc" + xtxt + "world!");
+ });
+
+ // create some threads to log "def" messages
+ addThread(tend, err, xtxt -> {
+ logger.info("hello def" + xtxt + "world!");
+ });
+
+ // create some threads to get extractions
+ addThread(tend, err, xtxt -> {
+ app.getExtracted();
+ });
+
+ // create some threads to clear extractions
+ addThread(tend, err, xtxt -> {
+ app.clearExtractions();
+
+ // don't want to clear the list too frequently
+ // so sleep a bit in between
+ try {
+ Thread.sleep(10 + Integer.valueOf(xtxt));
+
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw e;
+ }
+ });
+
+ /*
+ * Finally ready to start.
+ */
+
+ // start all of the threads
+ for (Thread t : threads) {
+ t.setDaemon(true);
+ t.start();
+ }
+
+ // wait for each thread to stop
+ for (Thread t : threads) {
+ t.join(THREAD_WAIT_MS);
+ assertFalse(t.isAlive());
+ }
+
+ // ensure none of the threads threw an exception
+ assertFalse(err.get());
+ }
+
+ /**
+ * Adds multiple threads to perform some function repeatedly until the given
+ * time is reached.
+ *
+ * @param tend
+ * time, in milliseconds, when the test should terminate
+ * @param haderr
+ * this will be set to {@code true} if the function throws an
+ * exception other than an InterruptedException
+ * @param func
+ * function to be repeatedly invoked
+ */
+ private void addThread(long tend, AtomicBoolean haderr, VoidFunction func) {
+ // number of threads of each type to create
+ int neach = 3;
+
+ for (int x = 0; x < neach; ++x) {
+ String xtxt = String.valueOf(x);
+
+ threads.add(new Thread() {
+ @Override
+ public void run() {
+ try {
+ while (System.currentTimeMillis() < tend) {
+ func.apply(xtxt);
+ }
+
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+
+ } catch (Exception ex) {
+ haderr.set(true);
+ }
+ }
+ });
+
+ }
+ }
+
+ /**
+ * Makes an appender that recognizes the given set of strings.
+ *
+ * @param strings
+ * regular expressions to be matched
+ * @return a new appender
+ */
+ private ExtractAppender makeAppender(String... strings) {
+ ExtractAppender p = new ExtractAppender(strings);
+
+ addAppender(p);
+
+ return p;
+ }
+
+ /**
+ * Adds an appender to the logger.
+ *
+ * @param app
+ * appender to be added
+ */
+ private void addAppender(ExtractAppender app) {
+ app.setContext(logger.getLoggerContext());
+ app.start();
+
+ logger.addAppender(app);
+ }
+
+ /**
+ * Converts an array of strings into a list of strings.
+ *
+ * @param strings
+ * array of strings
+ * @return a list of the strings
+ */
+ private List<String> strList(String... strings) {
+ return Arrays.asList(strings);
+ }
+
+ @FunctionalInterface
+ public interface VoidFunction {
+ public void apply(String text) throws InterruptedException;
+ }
+}
diff --git a/utils-test/src/test/resources/logback-test.xml b/utils-test/src/test/resources/logback-test.xml
new file mode 100644
index 00000000..20869a43
--- /dev/null
+++ b/utils-test/src/test/resources/logback-test.xml
@@ -0,0 +1,37 @@
+<!--
+ ============LICENSE_START=======================================================
+ integrity-monitor
+ ================================================================================
+ Copyright (C) 2018 AT&T Intellectual Property. All rights reserved.
+ ================================================================================
+ 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.
+ ============LICENSE_END=========================================================
+ -->
+
+<!-- Controls the output of logs for JUnit tests -->
+
+<configuration>
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+ <Pattern>
+ %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M\(%line\) - %msg%n
+ </Pattern>
+ </encoder>
+ </appender>
+
+ <root level="debug">
+ <appender-ref ref="STDOUT" />
+ </root>
+
+</configuration>