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.db;
015
016import ch.qos.logback.classic.LoggerContext;
017import ch.qos.logback.classic.joran.JoranConfigurator;
018import ch.qos.logback.core.db.DriverManagerConnectionSource;
019import ch.qos.logback.core.joran.spi.JoranException;
020import ch.qos.logback.core.testUtil.RandomUtil;
021import ch.qos.logback.core.testUtil.StatusChecker;
022import ch.qos.logback.core.util.EnvUtil;
023import ch.qos.logback.core.util.StatusPrinter;
024import org.junit.*;
025import org.slf4j.Logger;
026import org.slf4j.MDC;
027
028import java.net.InetAddress;
029import java.sql.Connection;
030import java.sql.ResultSet;
031import java.sql.SQLException;
032import java.sql.Statement;
033import java.util.HashMap;
034import java.util.Map;
035
036import static org.junit.Assert.*;
037
038public class DBAppenderIntegrationTest {
039
040    static String LOCAL_HOST_NAME;
041    static String[] CONFORMING_HOST_LIST = new String[] { "Orion" };
042    static String[] POSTGRES_CONFORMING_HOST_LIST = new String[] { "haro" };
043    static String[] MYSQL_CONFORMING_HOST_LIST = new String[] { "xharo" };
044    static String[] ORACLE_CONFORMING_HOST_LIST = new String[] { "xharo" };
045
046    int diff = RandomUtil.getPositiveInt();
047    LoggerContext lc = new LoggerContext();
048
049    @BeforeClass
050    public static void setUpBeforeClass() throws Exception {
051        InetAddress localhostIA = InetAddress.getLocalHost();
052        LOCAL_HOST_NAME = localhostIA.getHostName();
053    }
054
055    @AfterClass
056    public static void tearDownAfterClass() throws Exception {
057    }
058
059    @Before
060    public void setUp() throws Exception {
061        lc.setName("lc" + diff);
062    }
063
064    @After
065    public void tearDown() throws Exception {
066        // lc will never be used again
067        lc.stop();
068    }
069
070    DriverManagerConnectionSource getConnectionSource() {
071        ch.qos.logback.classic.Logger root = (ch.qos.logback.classic.Logger) lc.getLogger(Logger.ROOT_LOGGER_NAME);
072
073        DBAppender dbAppender = (DBAppender) root.getAppender("DB");
074        assertNotNull(dbAppender);
075        return (DriverManagerConnectionSource) dbAppender.getConnectionSource();
076
077    }
078
079    public void doTest(String configFile) throws JoranException, SQLException {
080        JoranConfigurator configurator = new JoranConfigurator();
081        configurator.setContext(lc);
082        configurator.doConfigure(configFile);
083
084        Logger logger = lc.getLogger(DBAppenderIntegrationTest.class);
085
086        // the key userid is used in SiftingAppender test
087        // suffix with diff to avoid collision
088        MDC.put("userid" + diff, "user" + diff);
089        int runLength = 5;
090        for (int i = 1; i <= runLength; i++) {
091            logger.debug("This is a debug message. Message number: " + (diff + i));
092        }
093
094        Exception e = new Exception("Just testing", getCause());
095        logger.error("At last an error.", e);
096
097        StatusPrinter.printInCaseOfErrorsOrWarnings(lc);
098
099        long lastEventId = getLastEventId();
100        verify(lastEventId);
101
102        // check that there were no errors
103        StatusChecker checker = new StatusChecker(lc);
104        checker.assertIsErrorFree();
105    }
106
107    long getLastEventId() throws SQLException {
108        DriverManagerConnectionSource cs = getConnectionSource();
109
110        Connection con = cs.getConnection();
111        Statement statement = con.createStatement();
112        statement.setMaxRows(1);
113        ResultSet rs = statement.executeQuery("select event_id from logging_event order by event_id desc");
114        rs.next();
115        long eventId = rs.getLong(1);
116        rs.close();
117        statement.close();
118        return eventId;
119    }
120
121    void verify(long lastEventId) throws SQLException {
122        verifyDebugMsg(lastEventId);
123        verifyException(lastEventId);
124        verifyProperty(lastEventId);
125
126    }
127
128    void verifyDebugMsg(long lastEventId) throws SQLException {
129        DriverManagerConnectionSource cs = getConnectionSource();
130        Connection con = cs.getConnection();
131        Statement statement = con.createStatement();
132        ResultSet rs = statement.executeQuery("select formatted_message from logging_event where event_id='" + (lastEventId - 1) + "'");
133        rs.next();
134        String msg = rs.getString(1);
135        assertEquals("This is a debug message. Message number: " + (diff + 5), msg);
136    }
137
138    void verifyProperty(long lastEventId) throws SQLException {
139        DriverManagerConnectionSource cs = getConnectionSource();
140        Connection con = cs.getConnection();
141        Statement statement = con.createStatement();
142        ResultSet rs = statement.executeQuery("select mapped_key, mapped_value from logging_event_property where event_id='" + (lastEventId - 1) + "'");
143
144        Map<String, String> witness = lc.getCopyOfPropertyMap();
145        witness.putAll(MDC.getCopyOfContextMap());
146
147        Map<String, String> map = new HashMap<String, String>();
148        while (rs.next()) {
149            String key = rs.getString(1);
150            String val = rs.getString(2);
151            map.put(key, val);
152        }
153
154        assertEquals(witness, map);
155    }
156
157    void verifyException(long lastEventId) throws SQLException {
158        DriverManagerConnectionSource cs = getConnectionSource();
159        Connection con = cs.getConnection();
160        Statement statement = con.createStatement();
161        ResultSet rs = statement.executeQuery("select trace_line from logging_event_exception where event_id='" + (lastEventId) + "' AND I='0'");
162        rs.next();
163        String traceLine = rs.getString(1);
164        assertEquals("java.lang.Exception: Just testing", traceLine);
165    }
166
167    Throwable getCause() {
168        return new IllegalStateException("test cause");
169    }
170
171    static boolean isConformingHostAndJDK16OrHigher(String[] conformingHostList) {
172        if (!EnvUtil.isJDK6OrHigher()) {
173            return false;
174        }
175        for (String conformingHost : conformingHostList) {
176            if (conformingHost.equalsIgnoreCase(LOCAL_HOST_NAME)) {
177                return true;
178            }
179        }
180        return false;
181    }
182
183    static boolean isConformingHostAndJDK16OrHigher() {
184        return isConformingHostAndJDK16OrHigher(CONFORMING_HOST_LIST);
185    }
186
187    @Test
188    public void sqlserver() throws Exception {
189        // perform test only on conforming hosts
190        if (!isConformingHostAndJDK16OrHigher()) {
191            return;
192        }
193        doTest("src/test/input/integration/db/sqlserver-with-driver.xml");
194    }
195
196    @Test
197    public void oracle10g() throws Exception {
198        // perform test only on conforming hosts
199        if (!isConformingHostAndJDK16OrHigher(ORACLE_CONFORMING_HOST_LIST)) {
200            return;
201        }
202        doTest("src/test/input/integration/db/oracle10g-with-driver.xml");
203    }
204
205    @Test
206    @Ignore
207    public void oracle11g() throws Exception {
208        // perform test only on conforming hosts
209        if (!isConformingHostAndJDK16OrHigher()) {
210            return;
211        }
212        doTest("src/test/input/integration/db/oracle11g-with-driver.xml");
213    }
214
215    @Test
216    public void mysql() throws Exception {
217        // perform test only on conforming hosts
218        if (!isConformingHostAndJDK16OrHigher(MYSQL_CONFORMING_HOST_LIST)) {
219            return;
220        }
221        doTest("src/test/input/integration/db/mysql-with-driver.xml");
222    }
223
224    @Test
225    public void postgres() throws Exception {
226        // perform test only on conforming hosts
227        if (!isConformingHostAndJDK16OrHigher(POSTGRES_CONFORMING_HOST_LIST)) {
228            return;
229        }
230        System.out.println("running postgres() test");
231        doTest("src/test/input/integration/db/postgresql-with-driver.xml");
232    }
233
234}