diff --git a/src/integrationTest/java/org/opensearch/security/http/JwtAuthenticationTests.java b/src/integrationTest/java/org/opensearch/security/http/JwtAuthenticationTests.java index 7f5d21ea58..bf8af72854 100644 --- a/src/integrationTest/java/org/opensearch/security/http/JwtAuthenticationTests.java +++ b/src/integrationTest/java/org/opensearch/security/http/JwtAuthenticationTests.java @@ -39,6 +39,7 @@ import org.opensearch.test.framework.cluster.TestRestClient.HttpResponse; import org.opensearch.test.framework.log.LogsRule; +import static java.nio.charset.StandardCharsets.US_ASCII; import static org.apache.http.HttpHeaders.AUTHORIZATION; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; @@ -89,7 +90,7 @@ public class JwtAuthenticationTests { public static final String QA_SONG_INDEX_NAME = String.format("song_lyrics_%s", QA_DEPARTMENT); private static final KeyPair KEY_PAIR = Keys.keyPairFor(SignatureAlgorithm.RS256); - private static final String PUBLIC_KEY = new String(Base64.getEncoder().encode(KEY_PAIR.getPublic().getEncoded())); + private static final String PUBLIC_KEY = new String(Base64.getEncoder().encode(KEY_PAIR.getPublic().getEncoded()), US_ASCII); static final TestSecurityConfig.User ADMIN_USER = new TestSecurityConfig.User("admin").roles(ALL_ACCESS); @@ -186,7 +187,7 @@ public void shouldAuthenticateWithJwtToken_failureIncorrectFormatOfToken() { HttpResponse response = client.getAuthInfo(); response.assertStatusCode(401); - logsRule.assertThatContain(String.format("No JWT token found in '%s' header.", JWT_AUTH_HEADER)); + logsRule.assertThatContain(String.format("No JWT token found in '%s' header header", JWT_AUTH_HEADER)); } } diff --git a/src/integrationTest/java/org/opensearch/test/framework/log/LogCapturingAppender.java b/src/integrationTest/java/org/opensearch/test/framework/log/LogCapturingAppender.java index 83baf031c7..11a59f470d 100644 --- a/src/integrationTest/java/org/opensearch/test/framework/log/LogCapturingAppender.java +++ b/src/integrationTest/java/org/opensearch/test/framework/log/LogCapturingAppender.java @@ -33,24 +33,53 @@ import static org.opensearch.test.framework.log.LogCapturingAppender.PLUGIN_NAME; +/** +*

The class acts as Log4j2 appender with a special purpose. The appender is used to capture logs which are generated during tests and +* then test can examine logs. To use the appender it is necessary to:

+*
    +*
  1. Add package with appender to log4j2 package scan in Log4j2 configuration file
  2. +*
  3. Create appender in log4j2 configuration
  4. +*
  5. Assign required loggers to appender
  6. +*
  7. Enable appender for certain classes with method {@link #enable(String...)}. Each test can enable appender for distinct classes
  8. +*
+*/ @Plugin(name = PLUGIN_NAME, category = Core.CATEGORY_NAME, elementType = Appender.ELEMENT_TYPE, printObject = true) public class LogCapturingAppender extends AbstractAppender { public final static String PLUGIN_NAME = "LogCapturingAppender"; + /** + * Appender stores only last MAX_SIZE messages to avoid excessive RAM memory usage. + */ public static final int MAX_SIZE = 100; + + /** + * Buffer for captured log messages + */ private static final Buffer messages = BufferUtils.synchronizedBuffer(new CircularFifoBuffer(MAX_SIZE)); + /** + * Log messages are stored in buffer {@link #messages} only for classes which are added to the {@link #activeLoggers} set. + */ private static final Set activeLoggers = Collections.synchronizedSet(new HashSet<>()); protected LogCapturingAppender(String name, Filter filter, Layout layout, boolean ignoreExceptions, Property[] properties) { super(name, filter, layout, ignoreExceptions, properties); } + /** + * Method used by Log4j2 to create appender + * @param name appender name from Log4j2 configuration + * @return newly created appender + */ @PluginFactory public static LogCapturingAppender createAppender(@PluginAttribute(value = "name", defaultString = "logCapturingAppender") String name) { return new LogCapturingAppender(name, null, null, true, Property.EMPTY_ARRAY); } + /** + * Method invoked by Log4j2 to append log events + * @param event The LogEvent, represents log message. + */ @Override public void append(LogEvent event) { String loggerName = event.getLoggerName(); @@ -60,16 +89,27 @@ public void append(LogEvent event) { } } + /** + * To collect log messages form given logger the logger name must be passed to {@link #enable(String...)} method. + * @param loggerNames logger names + */ public static void enable(String...loggerNames) { disable(); activeLoggers.addAll(Arrays.asList(loggerNames)); } + /** + * Invocation cause that appender stops collecting log messages. Additionally, memory used by collected messages so far is released. + */ public static void disable() { activeLoggers.clear(); messages.clear(); } + /** + * Is used to obtain gathered log messages + * @return Log messages + */ public static List getLogMessages() { return new ArrayList<>(messages); } diff --git a/src/integrationTest/java/org/opensearch/test/framework/log/LogsRule.java b/src/integrationTest/java/org/opensearch/test/framework/log/LogsRule.java index 4a0b35dd36..34fe6f4455 100644 --- a/src/integrationTest/java/org/opensearch/test/framework/log/LogsRule.java +++ b/src/integrationTest/java/org/opensearch/test/framework/log/LogsRule.java @@ -18,10 +18,20 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasItem; +/** +* The class is a JUnit 4 rule and enables developers to write assertion related to log messages generated in the course of test. To use +* {@link LogsRule} appender {@link LogCapturingAppender} must be properly configured. The rule also manages {@link LogCapturingAppender} +* so that memory occupied by gathered log messages is released after each test. +*/ public class LogsRule extends ExternalResource { private final String[] loggerNames; + /** + * Constructor used to start gathering log messages from certain loggers + * @param loggerNames Loggers names. Log messages are collected only if the log message is associated with the logger with a name which + * is present in loggerNames parameter. + */ public LogsRule(String...loggerNames) { this.loggerNames = Objects.requireNonNull(loggerNames, "Logger names are required"); } @@ -36,6 +46,10 @@ protected void after() { LogCapturingAppender.disable(); } + /** + * Check if during the tests certain log message was logged + * @param expectedLogMessage expected log message + */ public void assertThatContain(String expectedLogMessage) { List messages = LogCapturingAppender.getLogMessages(); String reason = reasonMessage(expectedLogMessage, messages);