001/**
002 * Logback: the reliable, generic, fast and flexible logging framework.
003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved.
004 *
005 * This program and the accompanying materials are dual-licensed under
006 * either the terms of the Eclipse Public License v1.0 as published by
007 * the Eclipse Foundation
008 *
009 *   or (per the licensee's choosing)
010 *
011 * under the terms of the GNU Lesser General Public License version 2.1
012 * as published by the Free Software Foundation.
013 */
014package ch.qos.logback.classic.util;
015
016import static org.junit.Assert.assertEquals;
017import static org.junit.Assert.assertNotNull;
018import static org.junit.Assert.assertNull;
019import static org.junit.Assert.assertSame;
020import static org.junit.Assert.assertTrue;
021import static org.junit.Assert.fail;
022import static org.junit.Assume.assumeTrue;
023
024import java.io.IOException;
025import java.io.InputStream;
026import java.net.MalformedURLException;
027import java.net.URL;
028import java.util.Enumeration;
029import java.util.List;
030import java.util.Vector;
031
032import org.junit.After;
033import org.junit.Before;
034import org.junit.Ignore;
035import org.junit.Test;
036
037import ch.qos.logback.classic.ClassicConstants;
038import ch.qos.logback.classic.ClassicTestConstants;
039import ch.qos.logback.classic.Logger;
040import ch.qos.logback.classic.LoggerContext;
041import ch.qos.logback.classic.spi.ILoggingEvent;
042import ch.qos.logback.core.Appender;
043import ch.qos.logback.core.ConsoleAppender;
044import ch.qos.logback.core.CoreConstants;
045import ch.qos.logback.core.LogbackException;
046import ch.qos.logback.core.joran.spi.JoranException;
047import ch.qos.logback.core.status.StatusListener;
048import ch.qos.logback.core.testUtil.TrivialStatusListener;
049import ch.qos.logback.core.util.Loader;
050
051public class ContextInitializerTest {
052
053    LoggerContext loggerContext = new LoggerContext();
054    Logger root = loggerContext.getLogger(Logger.ROOT_LOGGER_NAME);
055
056    @Before
057    public void setUp() throws Exception {
058    }
059
060    @After
061    public void tearDown() throws Exception {
062        System.clearProperty(ClassicConstants.CONFIG_FILE_PROPERTY);
063        System.clearProperty(CoreConstants.STATUS_LISTENER_CLASS_KEY);
064        MockConfigurator.context = null;
065    }
066
067    @Test
068    @Ignore
069    // this test works only if logback-test.xml or logback.xml files are on the classpath.
070    // However, this is something we try to avoid in order to simplify the life
071    // of users trying to follow the manual and logback-examples from an IDE
072    public void reset() throws JoranException {
073        {
074            new ContextInitializer(loggerContext).autoConfig();
075            Appender<ILoggingEvent> appender = root.getAppender("STDOUT");
076            assertNotNull(appender);
077            assertTrue(appender instanceof ConsoleAppender);
078        }
079        {
080            loggerContext.stop();
081            Appender<ILoggingEvent> appender = root.getAppender("STDOUT");
082            assertNull(appender);
083        }
084    }
085
086    @Test
087    public void autoConfigFromSystemProperties() throws JoranException {
088        doAutoConfigFromSystemProperties(ClassicTestConstants.INPUT_PREFIX + "autoConfig.xml");
089        doAutoConfigFromSystemProperties("autoConfigAsResource.xml");
090        // test passing a URL. note the relative path syntax with file:src/test/...
091        doAutoConfigFromSystemProperties("file:" + ClassicTestConstants.INPUT_PREFIX + "autoConfig.xml");
092    }
093
094    public void doAutoConfigFromSystemProperties(String val) throws JoranException {
095        // lc.reset();
096        System.setProperty(ClassicConstants.CONFIG_FILE_PROPERTY, val);
097        new ContextInitializer(loggerContext).autoConfig();
098        Appender<ILoggingEvent> appender = root.getAppender("AUTO_BY_SYSTEM_PROPERTY");
099        assertNotNull(appender);
100    }
101
102    @Test
103    public void autoConfigFromServiceLoaderJDK6andAbove() throws Exception {
104        assumeTrue(!isJDK5());
105        setupMockServiceLoader();
106        assertNull(MockConfigurator.context);
107        new ContextInitializer(loggerContext).autoConfig();
108        assertNotNull(MockConfigurator.context);
109        assertSame(loggerContext, MockConfigurator.context);
110    }
111
112    @Test
113    public void autoConfigFromServiceLoaderJDK5() throws Exception {
114        assumeTrue(isJDK5());
115        setupMockServiceLoader();
116        assertNull(MockConfigurator.context);
117        new ContextInitializer(loggerContext).autoConfig();
118        assertNull(MockConfigurator.context);
119    }
120
121    @Test
122    public void autoStatusListener() throws JoranException {
123        System.setProperty(CoreConstants.STATUS_LISTENER_CLASS_KEY, TrivialStatusListener.class.getName());
124        List<StatusListener> statusListenerList = loggerContext.getStatusManager().getCopyOfStatusListenerList();
125        assertEquals(0, statusListenerList.size());
126        doAutoConfigFromSystemProperties(ClassicTestConstants.INPUT_PREFIX + "autoConfig.xml");
127        statusListenerList = loggerContext.getStatusManager().getCopyOfStatusListenerList();
128        assertTrue(statusListenerList.size() + " should be 1", statusListenerList.size() == 1);
129        // LOGBACK-767
130        TrivialStatusListener tsl = (TrivialStatusListener) statusListenerList.get(0);
131        assertTrue("expecting at least one event in list", tsl.list.size() > 0);
132    }
133
134    @Test
135    public void autoOnConsoleStatusListener() throws JoranException {
136        System.setProperty(CoreConstants.STATUS_LISTENER_CLASS_KEY, CoreConstants.SYSOUT);
137        List<StatusListener> sll = loggerContext.getStatusManager().getCopyOfStatusListenerList();
138        assertEquals(0, sll.size());
139        doAutoConfigFromSystemProperties(ClassicTestConstants.INPUT_PREFIX + "autoConfig.xml");
140        sll = loggerContext.getStatusManager().getCopyOfStatusListenerList();
141        assertTrue(sll.size() + " should be 1", sll.size() == 1);
142    }
143
144    @Test
145    public void shouldConfigureFromXmlFile() throws MalformedURLException, JoranException {
146        LoggerContext loggerContext = new LoggerContext();
147        ContextInitializer initializer = new ContextInitializer(loggerContext);
148        assertNull(loggerContext.getObject(CoreConstants.SAFE_JORAN_CONFIGURATION));
149
150        URL configurationFileUrl = Loader.getResource("BOO_logback-test.xml", Thread.currentThread().getContextClassLoader());
151        initializer.configureByResource(configurationFileUrl);
152
153        assertNotNull(loggerContext.getObject(CoreConstants.SAFE_JORAN_CONFIGURATION));
154    }
155
156//    @Test
157//    public void shouldConfigureFromGroovyScript() throws MalformedURLException, JoranException {
158//        LoggerContext loggerContext = new LoggerContext();
159//        ContextInitializer initializer = new ContextInitializer(loggerContext);
160//        assertNull(loggerContext.getObject(CoreConstants.CONFIGURATION_WATCH_LIST));
161//
162//        URL configurationFileUrl = Loader.getResource("test.groovy", Thread.currentThread().getContextClassLoader());
163//        initializer.configureByResource(configurationFileUrl);
164//
165//        assertNotNull(loggerContext.getObject(CoreConstants.CONFIGURATION_WATCH_LIST));
166//    }
167
168    @Test
169    public void shouldThrowExceptionIfUnexpectedConfigurationFileExtension() throws JoranException {
170        LoggerContext loggerContext = new LoggerContext();
171        ContextInitializer initializer = new ContextInitializer(loggerContext);
172
173        URL configurationFileUrl = Loader.getResource("README.txt", Thread.currentThread().getContextClassLoader());
174        try {
175            initializer.configureByResource(configurationFileUrl);
176            fail("Should throw LogbackException");
177        } catch (LogbackException expectedException) {
178            // pass
179        }
180    }
181
182    private static boolean isJDK5() {
183        String ver = System.getProperty("java.version");
184        boolean jdk5 = ver.startsWith("1.5.") || ver.equals("1.5");
185        return jdk5;
186    }
187
188    private void setupMockServiceLoader() {
189        final ClassLoader realLoader = EnvUtil.class.getClassLoader();
190        EnvUtil.testServiceLoaderClassLoader = new WrappedClassLoader(realLoader) {
191
192            @Override
193            public Enumeration<URL> getResources(String name) throws IOException {
194                final Enumeration<URL> r;
195                if (name.endsWith("META-INF/services/ch.qos.logback.classic.spi.Configurator")) {
196                    Vector<URL> vs = new Vector<URL>();
197                    URL u = super.getResource("FAKE_META_INF_SERVICES_ch_qos_logback_classic_spi_Configurator");
198                    vs.add(u);
199                    return vs.elements();
200                } else {
201                    r = super.getResources(name);
202                }
203                return r;
204            }
205        };
206    }
207
208    static class WrappedClassLoader extends ClassLoader {
209        final ClassLoader delegate;
210
211        public WrappedClassLoader(ClassLoader delegate) {
212            super();
213            this.delegate = delegate;
214        }
215
216        public Class<?> loadClass(String name) throws ClassNotFoundException {
217            return delegate.loadClass(name);
218        }
219
220        public URL getResource(String name) {
221            return delegate.getResource(name);
222        }
223
224        public Enumeration<URL> getResources(String name) throws IOException {
225            return delegate.getResources(name);
226        }
227
228        public InputStream getResourceAsStream(String name) {
229            return delegate.getResourceAsStream(name);
230        }
231
232        public void setDefaultAssertionStatus(boolean enabled) {
233            delegate.setDefaultAssertionStatus(enabled);
234        }
235
236        public void setPackageAssertionStatus(String packageName, boolean enabled) {
237            delegate.setPackageAssertionStatus(packageName, enabled);
238        }
239
240        public void setClassAssertionStatus(String className, boolean enabled) {
241            delegate.setClassAssertionStatus(className, enabled);
242        }
243
244        public void clearAssertionStatus() {
245            delegate.clearAssertionStatus();
246        }
247    }
248
249}