1   /**
2    * Logback: the generic, reliable, fast and flexible logging framework.
3    * 
4    * Copyright (C) 2000-2008, QOS.ch
5    * 
6    * This library is free software, you can redistribute it and/or modify it under
7    * the terms of the GNU Lesser General Public License as published by the Free
8    * Software Foundation.
9    */
10  package org.slf4j.impl;
11  
12  import static org.junit.Assert.assertEquals;
13  import static org.junit.Assert.assertNotNull;
14  import static org.junit.Assert.assertNull;
15  import static org.junit.Assert.assertTrue;
16  
17  import java.util.HashMap;
18  import java.util.Random;
19  
20  import org.junit.Test;
21  import org.slf4j.MDC;
22  
23  public class LogbackMDCAdapterTest {
24  
25    final static String A_SUFFIX = "A_SUFFIX";
26  
27    int diff = new Random().nextInt();
28  
29    /**
30     * Test that CopyOnInheritThreadLocal does not barf when the 
31     * MDC hashmap is null
32     * 
33     * @throws InterruptedException
34     */
35    @Test
36    public void lbclassic77() throws InterruptedException {
37      LogbackMDCAdapter lma = new LogbackMDCAdapter();
38  
39      HashMap<String, String> parentHM = getHashMapFromMDCAdapter(lma);
40      assertNull(parentHM);
41      
42      ChildThreadForMDCAdapter childThread = new ChildThreadForMDCAdapter(lma);
43      childThread.start();
44      childThread.join();
45      assertTrue(childThread.successul);
46      assertNull(childThread.childHM);
47    }
48    
49    class ChildThreadForMDCAdapter extends Thread {
50  
51      LogbackMDCAdapter logbackMDCAdapter;
52      boolean successul;
53      HashMap<String, String> childHM;
54  
55      ChildThreadForMDCAdapter(LogbackMDCAdapter logbackMDCAdapter) {
56        this.logbackMDCAdapter = logbackMDCAdapter;
57      }
58      
59      @Override
60      public void run() {
61        childHM = getHashMapFromMDCAdapter(logbackMDCAdapter);
62        logbackMDCAdapter.get("");
63        successul = true;
64      }
65    }
66  
67    // ================================================= 
68    /**
69     * Test that LogbackMDCAdapter copies its hashmap when a child
70     * thread inherits it.
71     * 
72     * @throws InterruptedException
73     */
74    @Test
75    public void copyOnInheritence() throws InterruptedException {
76      String mdcKey = "x" + diff;
77      String otherMDCKey = "o" + diff;
78      MDC.put(mdcKey, mdcKey + A_SUFFIX);
79  
80      HashMap<String, String> parentHM = getHashMapFromMDC();
81  
82      ChildThreadForMDC childThread = new ChildThreadForMDC(mdcKey, otherMDCKey);
83      childThread.start();
84      childThread.join();
85  
86      assertNull(MDC.get(otherMDCKey));
87      assertTrue(childThread.successul);
88      assertTrue(parentHM != childThread.childHM);
89    }
90  
91     
92    class ChildThreadForMDC extends Thread {
93  
94      String mdcKey;
95      String otherMDCKey;
96      boolean successul;
97      HashMap<String, String> childHM;
98  
99      ChildThreadForMDC(String mdcKey, String otherMDCKey) {
100       this.mdcKey = mdcKey;
101       this.otherMDCKey = otherMDCKey;
102     }
103 
104     @Override
105     public void run() {
106       childHM = getHashMapFromMDC();
107 
108       MDC.put(otherMDCKey, otherMDCKey + A_SUFFIX);
109       assertNotNull(MDC.get(mdcKey));
110       assertEquals(mdcKey + A_SUFFIX, MDC.get(mdcKey));
111       assertEquals(otherMDCKey + A_SUFFIX, MDC.get(otherMDCKey));
112       successul = true;
113     }
114   }
115 
116   HashMap<String, String> getHashMapFromMDCAdapter(LogbackMDCAdapter lma) {
117     CopyOnInheritThreadLocal copyOnInheritThreadLocal = lma.copyOnInheritThreadLocal;
118     return copyOnInheritThreadLocal.get();
119   }
120 
121   HashMap<String, String> getHashMapFromMDC() {
122     LogbackMDCAdapter lma = (LogbackMDCAdapter) MDC.getMDCAdapter();
123     CopyOnInheritThreadLocal copyOnInheritThreadLocal = lma.copyOnInheritThreadLocal;
124     return copyOnInheritThreadLocal.get();
125   }
126 }