ConfigurationWatchListTest.java

/*
 * Logback: the reliable, generic, fast and flexible logging framework.
 * Copyright (C) 1999-2026, QOS.ch. All rights reserved.
 *
 * This program and the accompanying materials are dual-licensed under
 * either the terms of the Eclipse Public License v2.0 as published by
 * the Eclipse Foundation
 *
 *   or (per the licensee's choosing)
 *
 * under the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation.
 */

package ch.qos.logback.classic.blackbox.joran.spi;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.blackbox.joran.ReconfigureOnChangeTaskTest;
import ch.qos.logback.classic.blackbox.joran.ReconfigureTaskTestSupport;
import ch.qos.logback.core.CoreConstants;
import ch.qos.logback.core.joran.spi.ConfigurationWatchList;
import ch.qos.logback.core.joran.spi.HttpUtil;
import ch.qos.logback.core.joran.spi.JoranException;
import ch.qos.logback.core.testUtil.RandomUtil;
import jakarta.servlet.http.HttpServlet;
import org.junit.jupiter.api.*;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import static org.junit.jupiter.api.Assertions.*;

public class ConfigurationWatchListTest extends ReconfigureTaskTestSupport {

    static String BAZINGA_LOGGER_NAME = "com.bazinga";
    static String BAZINGA_LOGGER_SETUP_0 = "logback.logger."+BAZINGA_LOGGER_NAME+"=WARN";
    static String BAZINGA_LOGGER_SETUP_1 = "logback.logger."+BAZINGA_LOGGER_NAME+"=ERROR";

    int randomPort = RandomUtil.getRandomServerPort();
    ConfigEmbeddedJetty configEmbeddedJetty;
    ConfigurationWatchList cwl = new ConfigurationWatchList();
    static String FOO_PROPERTIES = "/foo.properties";
    String urlString = "http://127.0.0.1:"+randomPort+FOO_PROPERTIES;

    @BeforeEach
    public void setUp() throws Exception {
        Logger rootLogger = (Logger) LoggerFactory.getLogger( Logger.ROOT_LOGGER_NAME );
        rootLogger.setLevel(Level.INFO);

        configEmbeddedJetty = new ConfigEmbeddedJetty(randomPort);

        cwl.setContext(loggerContext);

        HttpServlet configServlet = new ConfigFileServlet(BAZINGA_LOGGER_SETUP_0);
        configEmbeddedJetty.getServletMap().put(FOO_PROPERTIES, configServlet);

        configEmbeddedJetty.init();

    }

    @AfterEach
    public void tearDown() throws Exception {
        configEmbeddedJetty.stop();
    }



    @Test
    public void testInfrastructure() throws MalformedURLException {
        String response = get(urlString);
        assertNotNull(response);
        Assertions.assertEquals(BAZINGA_LOGGER_SETUP_0, response);

        String setResponse1 = "bla bla";
        String response1 = post(urlString, setResponse1);
        assertEquals(response1, setResponse1);

        String response2 = get(urlString);
        assertEquals(response1, response2);
    }

    @Test
    public void smoke() throws MalformedURLException {
        URL url = new URL(urlString);
        cwl.addToWatchList(url);
        URL changedURL0 = cwl.changeDetectedInURL();
        assertNull(changedURL0);
      
        String setResponse1 = "bla bla";
        String response1 = post(urlString, setResponse1);
        assertEquals(response1, setResponse1);

        URL changedURL1 = cwl.changeDetectedInURL();
        assertEquals(urlString, changedURL1.toString());

        URL changedURL2 = cwl.changeDetectedInURL();
        assertNull(changedURL2);

        URL changedURL3 = cwl.changeDetectedInURL();
        assertNull(changedURL3);
    }

    @Disabled
    @Test
    public void propertiesFromHTTP() throws UnsupportedEncodingException, JoranException, InterruptedException, MalformedURLException {



        String propertiesURLStr = urlString;
        Logger bazingaLogger = loggerContext.getLogger(BAZINGA_LOGGER_NAME);

        assertEquals(BAZINGA_LOGGER_SETUP_0, get(urlString));

        String configurationStr = "<configuration debug=\"true\" scan=\"true\" scanPeriod=\"1 millisecond\"><propertiesConfigurator url=\"" + propertiesURLStr + "\"/></configuration>";

        configure(asBAIS(configurationStr));

        // allow for the first update
        Thread.sleep(50);
        assertEquals(Level.WARN, bazingaLogger.getLevel());
        System.out.println("first test passed with success");

        CountDownLatch changeDetectedLatch0 = registerChangeDetectedListener();
        CountDownLatch configurationDoneLatch0 = registerPartialConfigurationEndedSuccessfullyEventListener();

        String response1 = post(urlString, BAZINGA_LOGGER_SETUP_1);
        assertEquals(BAZINGA_LOGGER_SETUP_1, get(urlString));

        changeDetectedLatch0.await(100, TimeUnit.MICROSECONDS);
        configurationDoneLatch0.await(100, TimeUnit.MICROSECONDS);
        assertEquals(Level.ERROR, bazingaLogger.getLevel());
    }

}