dropwizard/dropwizard

View on GitHub
dropwizard-logging/src/test/java/io/dropwizard/logging/TcpSocketAppenderFactoryTest.java

Summary

Maintainability
A
2 hrs
Test Coverage
package io.dropwizard.logging;

import com.codahale.metrics.MetricRegistry;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.dropwizard.configuration.ResourceConfigurationSourceProvider;
import io.dropwizard.configuration.SubstitutingSourceProvider;
import io.dropwizard.configuration.YamlConfigurationFactory;
import io.dropwizard.jackson.Jackson;
import io.dropwizard.util.DataSize;
import io.dropwizard.util.Duration;
import io.dropwizard.validation.BaseValidator;
import org.apache.commons.text.StringSubstitutor;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.ServerSocket;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static org.assertj.core.api.Assertions.assertThat;

class TcpSocketAppenderFactoryTest {

    private final ObjectMapper objectMapper = Jackson.newObjectMapper();
    private final YamlConfigurationFactory<DefaultLoggingFactory> yamlConfigurationFactory = new YamlConfigurationFactory<>(
        DefaultLoggingFactory.class, BaseValidator.newValidator(), objectMapper, "dw-tcp");

    @BeforeEach
    void setUp() throws Exception {
        objectMapper.getSubtypeResolver().registerSubtypes(TcpSocketAppenderFactory.class);
    }

    private ServerSocket createServerSocket() {
        try {
            return new ServerSocket(0);
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }

    @Test
    void testParseConfig() throws Exception {
        DefaultLoggingFactory loggingFactory = yamlConfigurationFactory.build(new ResourceConfigurationSourceProvider(), "/yaml/logging-tcp-custom.yml");
        assertThat(loggingFactory.getAppenders())
            .singleElement()
            .isInstanceOfSatisfying(TcpSocketAppenderFactory.class, tcpAppenderFactory -> assertThat(tcpAppenderFactory)
                .satisfies(factory -> assertThat(factory.getHost()).isEqualTo("172.16.11.245"))
                .satisfies(factory -> assertThat(factory.getPort()).isEqualTo(17001))
                .satisfies(factory -> assertThat(factory.getConnectionTimeout()).isEqualTo(Duration.milliseconds(100)))
                .satisfies(factory -> assertThat(factory.getSendBufferSize()).isEqualTo(DataSize.kibibytes(2)))
                .satisfies(factory -> assertThat(factory.isImmediateFlush()).isFalse()));
    }

    @Test
    void testTestTcpLogging() throws Exception {
        try (ServerSocket serverSocket = createServerSocket(); TcpServer tcpServer = new TcpServer(serverSocket)) {
            Future<List<String>> receivedMessages = tcpServer.receive();
            DefaultLoggingFactory loggingFactory = yamlConfigurationFactory.build(new SubstitutingSourceProvider(
                    new ResourceConfigurationSourceProvider(),
                    new StringSubstitutor(Collections.singletonMap("tcp.server.port", serverSocket.getLocalPort()))),
                "yaml/logging-tcp.yml");
            loggingFactory.configure(new MetricRegistry(), "tcp-test");

            List<String> loggedMessages = generateLogs(LoggerFactory.getLogger("com.example.app"));
            loggingFactory.reset();

            assertThat(receivedMessages.get(1, TimeUnit.MINUTES))
                .hasSize(100)
                .allSatisfy(s -> assertThat(s).startsWith("INFO"))
                // Strip preamble from e.g. "INFO  [2021-11-20 10:23:57,620] com.example.app: Application log 0"
                .extracting(s -> s.substring(s.lastIndexOf("com.example.app: ") + "com.example.app: ".length()))
                .containsExactlyElementsOf(loggedMessages);
        }
    }

    @Test
    void testBufferingTcpLogging() throws Exception {
        try (ServerSocket serverSocket = createServerSocket(); TcpServer tcpServer = new TcpServer(serverSocket)) {
            Future<List<String>> receivedMessages = tcpServer.receive();
            DefaultLoggingFactory loggingFactory = yamlConfigurationFactory.build(new SubstitutingSourceProvider(
                    new ResourceConfigurationSourceProvider(),
                    new StringSubstitutor(Collections.singletonMap("tcp.server.port", serverSocket.getLocalPort()))),
                "yaml/logging-tcp-buffered.yml");
            loggingFactory.configure(new MetricRegistry(), "tcp-test");

            List<String> loggedMessages = generateLogs(LoggerFactory.getLogger("com.example.app"));
            // We have to flush the buffer manually
            loggingFactory.reset();

            assertThat(receivedMessages.get(1, TimeUnit.MINUTES))
                .allSatisfy(s -> assertThat(s).startsWith("INFO"))
                // Strip preamble from e.g. "INFO  [2021-11-20 10:23:57,620] com.example.app: Application log 0"
                .extracting(s -> s.substring(s.lastIndexOf("com.example.app: ") + "com.example.app: ".length()))
                .containsExactlyElementsOf(loggedMessages);
        }
    }

    private static List<String> generateLogs(final Logger logger) {
        return IntStream.range(0, 100)
            .mapToObj(i -> String.format("Application log %d", i))
            .peek(logger::info)
            .collect(Collectors.toList());
    }
}