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.core.sift;
015
016import ch.qos.logback.core.Appender;
017import ch.qos.logback.core.Context;
018import ch.qos.logback.core.ContextBase;
019import ch.qos.logback.core.joran.spi.JoranException;
020import ch.qos.logback.core.read.ListAppender;
021import ch.qos.logback.core.testUtil.RandomUtil;
022import org.junit.Before;
023import org.junit.Test;
024
025import java.util.ArrayList;
026import java.util.List;
027
028import static org.junit.Assert.*;
029
030/**
031 * Relatively straightforward unit tests for AppenderTracker.
032 */
033public class AppenderTrackerTest {
034
035    Context context = new ContextBase();
036    ListAppenderFactory listAppenderFactory = new ListAppenderFactory();
037    int diff = RandomUtil.getPositiveInt();
038    AppenderTracker<Object> appenderTracker = new AppenderTracker<Object>(context, listAppenderFactory);
039    String key = "k-" + diff;
040    long now = 3000;
041
042    @Before
043    public void setUp() {
044    }
045
046    @Test
047    public void removeStaleComponentsShouldNotBomb() {
048        appenderTracker.removeStaleComponents(now);
049        assertEquals(0, appenderTracker.getComponentCount());
050    }
051
052    @Test
053    public void findingTheInexistentShouldNotBomb() {
054        assertNull(appenderTracker.find(key));
055        now += AppenderTracker.DEFAULT_TIMEOUT + 1;
056        appenderTracker.removeStaleComponents(now);
057        assertNull(appenderTracker.find(key));
058    }
059
060    @Test
061    public void smoke() {
062        Appender<Object> a = appenderTracker.getOrCreate(key, now);
063        assertTrue(a.isStarted());
064        now += AppenderTracker.DEFAULT_TIMEOUT + 1;
065        appenderTracker.removeStaleComponents(now);
066        assertFalse(a.isStarted());
067        assertNull(appenderTracker.find(key));
068    }
069
070    @Test
071    public void endOfLivedAppendersShouldBeRemovedAfterLingeringTimeout() {
072        Appender<Object> a = appenderTracker.getOrCreate(key, now);
073        appenderTracker.endOfLife(key);
074        now += AppenderTracker.LINGERING_TIMEOUT + 1;
075        appenderTracker.removeStaleComponents(now);
076        assertFalse(a.isStarted());
077        a = appenderTracker.find(key);
078        assertNull(a);
079    }
080
081    @Test
082    public void endOfLivedAppenderShouldBeAvailableDuringLingeringPeriod() {
083        Appender<Object> a = appenderTracker.getOrCreate(key, now);
084        appenderTracker.endOfLife(key);
085        // clean
086        appenderTracker.removeStaleComponents(now);
087        Appender<Object> lingering = appenderTracker.getOrCreate(key, now);
088        assertTrue(lingering.isStarted());
089        assertTrue(a == lingering);
090        now += AppenderTracker.LINGERING_TIMEOUT + 1;
091        appenderTracker.removeStaleComponents(now);
092        assertFalse(a.isStarted());
093        a = appenderTracker.find(key);
094        assertNull(a);
095    }
096
097    @Test
098    public void trackerShouldHonorMaxComponentsParameter() {
099        List<Appender<Object>> appenderList = new ArrayList<>();
100        int max = 10;
101        appenderTracker.setMaxComponents(max);
102        for (int i = 0; i < (max + 1); i++) {
103            Appender<Object> a = appenderTracker.getOrCreate(key + "-" + i, now++);
104            appenderList.add(a);
105        }
106        // cleaning only happens in removeStaleComponents
107        appenderTracker.removeStaleComponents(now++);
108        assertEquals(max, appenderTracker.allKeys().size());
109        assertNull(appenderTracker.find(key + "-" + 0));
110        assertFalse(appenderList.get(0).isStarted());
111    }
112
113    @Test
114    public void trackerShouldHonorTimeoutParameter() {
115        List<Appender<Object>> appenderList = new ArrayList<Appender<Object>>();
116        int timeout = 2;
117        appenderTracker.setTimeout(timeout);
118        for (int i = 0; i <= timeout; i++) {
119            Appender<Object> a = appenderTracker.getOrCreate(key + "-" + i, now++);
120            appenderList.add(a);
121        }
122
123        long numComponentsCreated = timeout + 1;
124        assertEquals(numComponentsCreated, appenderTracker.allKeys().size());
125
126        // cleaning only happens in removeStaleComponents. The first appender should timeout
127        appenderTracker.removeStaleComponents(now++);
128
129        // the first appender should have been removed
130        assertEquals(numComponentsCreated - 1, appenderTracker.allKeys().size());
131        assertNull(appenderTracker.find(key + "-" + 0));
132        assertFalse(appenderList.get(0).isStarted());
133
134        // the other appenders should be in the tracker
135        for (int i = 1; i <= timeout; i++) {
136            assertNotNull(appenderTracker.find(key + "-" + i));
137            assertTrue(appenderList.get(i).isStarted());
138        }
139    }
140
141    // ======================================================================
142    static class ListAppenderFactory implements AppenderFactory<Object> {
143
144        public Appender<Object> buildAppender(Context context, String discriminatingValue) throws JoranException {
145            ListAppender<Object> la = new ListAppender<Object>();
146            la.setContext(context);
147            la.setName(discriminatingValue);
148            la.start();
149            return la;
150        }
151    }
152}