• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 The gRPC Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package io.grpc;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.logging.Handler;
24 import java.util.logging.LogRecord;
25 import java.util.logging.Logger;
26 import org.junit.After;
27 import org.junit.Before;
28 import org.junit.Test;
29 import org.junit.runner.RunWith;
30 import org.junit.runners.JUnit4;
31 
32 @RunWith(JUnit4.class)
33 public final class ThreadLocalContextStorageTest {
34   private static final Context.Key<Object> KEY = Context.key("test-key");
35   private static final ThreadLocalContextStorage storage = new ThreadLocalContextStorage();
36 
37   private Context contextBeforeTest;
38 
saveContext()39   @Before public void saveContext() {
40     contextBeforeTest = storage.doAttach(Context.ROOT);
41   }
42 
restoreContext()43   @After public void restoreContext() {
44     storage.detach(Context.ROOT, contextBeforeTest);
45   }
46 
47   @Test
detach_threadLocalClearedOnRoot()48   public void detach_threadLocalClearedOnRoot() {
49     Context context = Context.ROOT.withValue(KEY, new Object());
50     Context old = storage.doAttach(context);
51     assertThat(storage.current()).isSameInstanceAs(context);
52     assertThat(ThreadLocalContextStorage.localContext.get()).isSameInstanceAs(context);
53     storage.detach(context, old);
54     // thread local must contain null to avoid leaking our ClassLoader via ROOT
55     assertThat(ThreadLocalContextStorage.localContext.get()).isNull();
56   }
57 
58   @Test
detach_detachRoot()59   public void detach_detachRoot() {
60     final List<LogRecord> logs = new ArrayList<>();
61     Handler handler = new Handler() {
62       @Override public void publish(LogRecord record) {
63         logs.add(record);
64       }
65 
66       @Override public void flush() {}
67 
68       @Override public void close() {}
69     };
70 
71     // Explicitly choose ROOT as the current context
72     Context context = Context.ROOT;
73     Context old = storage.doAttach(context);
74 
75     // Attach and detach a random context
76     Context innerContext = Context.ROOT.withValue(KEY, new Object());
77     storage.detach(innerContext, storage.doAttach(innerContext));
78 
79     Logger logger = Logger.getLogger(ThreadLocalContextStorage.class.getName());
80     logger.addHandler(handler);
81     try {
82       // Make sure detaching ROOT doesn't log a warning
83       storage.detach(context, old);
84     } finally {
85       logger.removeHandler(handler);
86     }
87     assertThat(logs).isEmpty();
88   }
89 }
90