1 /* 2 * Copyright 2022 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 import static org.junit.Assert.fail; 21 22 import java.util.ArrayList; 23 import java.util.Arrays; 24 import java.util.Collections; 25 import java.util.List; 26 import java.util.regex.Pattern; 27 import org.junit.Test; 28 import org.junit.runner.RunWith; 29 import org.junit.runners.JUnit4; 30 31 @RunWith(JUnit4.class) 32 public class GlobalInterceptorsTest { 33 34 private final StaticTestingClassLoader classLoader = 35 new StaticTestingClassLoader( 36 getClass().getClassLoader(), Pattern.compile("io\\.grpc\\.[^.]+")); 37 38 @Test setInterceptorsTracers()39 public void setInterceptorsTracers() throws Exception { 40 Class<?> runnable = classLoader.loadClass(StaticTestingClassLoaderSet.class.getName()); 41 ((Runnable) runnable.getDeclaredConstructor().newInstance()).run(); 42 } 43 44 @Test setGlobalInterceptorsTracers_twice()45 public void setGlobalInterceptorsTracers_twice() throws Exception { 46 Class<?> runnable = classLoader.loadClass(StaticTestingClassLoaderSetTwice.class.getName()); 47 ((Runnable) runnable.getDeclaredConstructor().newInstance()).run(); 48 } 49 50 @Test getBeforeSet_clientInterceptors()51 public void getBeforeSet_clientInterceptors() throws Exception { 52 Class<?> runnable = 53 classLoader.loadClass( 54 StaticTestingClassLoaderGetBeforeSetClientInterceptor.class.getName()); 55 ((Runnable) runnable.getDeclaredConstructor().newInstance()).run(); 56 } 57 58 @Test getBeforeSet_serverInterceptors()59 public void getBeforeSet_serverInterceptors() throws Exception { 60 Class<?> runnable = 61 classLoader.loadClass( 62 StaticTestingClassLoaderGetBeforeSetServerInterceptor.class.getName()); 63 ((Runnable) runnable.getDeclaredConstructor().newInstance()).run(); 64 } 65 66 @Test getBeforeSet_serverStreamTracerFactories()67 public void getBeforeSet_serverStreamTracerFactories() throws Exception { 68 Class<?> runnable = 69 classLoader.loadClass( 70 StaticTestingClassLoaderGetBeforeSetServerStreamTracerFactory.class.getName()); 71 ((Runnable) runnable.getDeclaredConstructor().newInstance()).run(); 72 } 73 74 // UsedReflectively 75 public static final class StaticTestingClassLoaderSet implements Runnable { 76 @Override run()77 public void run() { 78 List<ClientInterceptor> clientInterceptorList = 79 new ArrayList<>(Arrays.asList(new NoopClientInterceptor())); 80 List<ServerInterceptor> serverInterceptorList = 81 new ArrayList<>(Arrays.asList(new NoopServerInterceptor())); 82 List<ServerStreamTracer.Factory> serverStreamTracerFactoryList = 83 new ArrayList<>( 84 Arrays.asList( 85 new NoopServerStreamTracerFactory(), new NoopServerStreamTracerFactory())); 86 87 GlobalInterceptors.setInterceptorsTracers( 88 clientInterceptorList, serverInterceptorList, serverStreamTracerFactoryList); 89 90 assertThat(GlobalInterceptors.getClientInterceptors()).isEqualTo(clientInterceptorList); 91 assertThat(GlobalInterceptors.getServerInterceptors()).isEqualTo(serverInterceptorList); 92 assertThat(GlobalInterceptors.getServerStreamTracerFactories()) 93 .isEqualTo(serverStreamTracerFactoryList); 94 } 95 } 96 97 public static final class StaticTestingClassLoaderSetTwice implements Runnable { 98 @Override run()99 public void run() { 100 GlobalInterceptors.setInterceptorsTracers( 101 new ArrayList<>(Arrays.asList(new NoopClientInterceptor())), 102 Collections.emptyList(), 103 new ArrayList<>(Arrays.asList(new NoopServerStreamTracerFactory()))); 104 try { 105 GlobalInterceptors.setInterceptorsTracers( 106 null, new ArrayList<>(Arrays.asList(new NoopServerInterceptor())), null); 107 fail("should have failed for calling setGlobalInterceptorsTracers() again"); 108 } catch (IllegalStateException e) { 109 assertThat(e).hasMessageThat().isEqualTo("Global interceptors and tracers are already set"); 110 } 111 } 112 } 113 114 public static final class StaticTestingClassLoaderGetBeforeSetClientInterceptor 115 implements Runnable { 116 @Override run()117 public void run() { 118 List<ClientInterceptor> clientInterceptors = GlobalInterceptors.getClientInterceptors(); 119 assertThat(clientInterceptors).isNull(); 120 121 try { 122 GlobalInterceptors.setInterceptorsTracers( 123 new ArrayList<>(Arrays.asList(new NoopClientInterceptor())), null, null); 124 fail("should have failed for invoking set call after get is already called"); 125 } catch (IllegalStateException e) { 126 assertThat(e).hasMessageThat().isEqualTo("Set cannot be called after any get call"); 127 } 128 } 129 } 130 131 public static final class StaticTestingClassLoaderGetBeforeSetServerInterceptor 132 implements Runnable { 133 @Override run()134 public void run() { 135 List<ServerInterceptor> serverInterceptors = GlobalInterceptors.getServerInterceptors(); 136 assertThat(serverInterceptors).isNull(); 137 138 try { 139 GlobalInterceptors.setInterceptorsTracers( 140 null, new ArrayList<>(Arrays.asList(new NoopServerInterceptor())), null); 141 fail("should have failed for invoking set call after get is already called"); 142 } catch (IllegalStateException e) { 143 assertThat(e).hasMessageThat().isEqualTo("Set cannot be called after any get call"); 144 } 145 } 146 } 147 148 public static final class StaticTestingClassLoaderGetBeforeSetServerStreamTracerFactory 149 implements Runnable { 150 @Override run()151 public void run() { 152 List<ServerStreamTracer.Factory> serverStreamTracerFactories = 153 GlobalInterceptors.getServerStreamTracerFactories(); 154 assertThat(serverStreamTracerFactories).isNull(); 155 156 try { 157 GlobalInterceptors.setInterceptorsTracers( 158 null, null, new ArrayList<>(Arrays.asList(new NoopServerStreamTracerFactory()))); 159 fail("should have failed for invoking set call after get is already called"); 160 } catch (IllegalStateException e) { 161 assertThat(e).hasMessageThat().isEqualTo("Set cannot be called after any get call"); 162 } 163 } 164 } 165 166 private static class NoopClientInterceptor implements ClientInterceptor { 167 @Override interceptCall( MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next)168 public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall( 169 MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) { 170 return next.newCall(method, callOptions); 171 } 172 } 173 174 private static class NoopServerInterceptor implements ServerInterceptor { 175 @Override interceptCall( ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next)176 public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall( 177 ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) { 178 return next.startCall(call, headers); 179 } 180 } 181 182 private static class NoopServerStreamTracerFactory extends ServerStreamTracer.Factory { 183 @Override newServerStreamTracer(String fullMethodName, Metadata headers)184 public ServerStreamTracer newServerStreamTracer(String fullMethodName, Metadata headers) { 185 throw new UnsupportedOperationException(); 186 } 187 } 188 } 189