1 // Copyright 2020 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package com.google.api.generator.gapic.model; 16 17 import static com.google.common.truth.Truth.assertThat; 18 import static org.junit.Assert.assertEquals; 19 import static org.junit.Assert.assertFalse; 20 import static org.junit.Assert.assertTrue; 21 22 import com.google.api.generator.gapic.protoparser.Parser; 23 import com.google.api.generator.gapic.protoparser.ServiceConfigParser; 24 import com.google.protobuf.Descriptors.FileDescriptor; 25 import com.google.protobuf.util.Durations; 26 import com.google.rpc.Code; 27 import com.google.showcase.v1beta1.EchoOuterClass; 28 import io.grpc.serviceconfig.MethodConfig; 29 import java.nio.file.Path; 30 import java.nio.file.Paths; 31 import java.util.Arrays; 32 import java.util.HashSet; 33 import java.util.List; 34 import java.util.Map; 35 import java.util.Optional; 36 import java.util.Set; 37 import org.junit.Test; 38 39 public class GapicServiceConfigTest { 40 41 private static final double EPSILON = 1e-4; 42 private static final String TESTDATA_DIRECTORY = "src/test/resources/"; 43 44 @Test serviceConfig_noConfigsFound()45 public void serviceConfig_noConfigsFound() { 46 FileDescriptor echoFileDescriptor = EchoOuterClass.getDescriptor(); 47 Service service = parseService(echoFileDescriptor); 48 49 String jsonFilename = "retrying_grpc_service_config.json"; 50 Path jsonPath = Paths.get(TESTDATA_DIRECTORY, jsonFilename); 51 Optional<GapicServiceConfig> serviceConfigOpt = ServiceConfigParser.parse(jsonPath.toString()); 52 assertTrue(serviceConfigOpt.isPresent()); 53 GapicServiceConfig serviceConfig = serviceConfigOpt.get(); 54 55 Map<String, GapicRetrySettings> retrySettings = serviceConfig.getAllGapicRetrySettings(service); 56 assertEquals(1, retrySettings.size()); 57 String retryParamsName = serviceConfig.getRetryParamsName(service, service.methods().get(0)); 58 assertEquals("no_retry_params", retryParamsName); 59 60 assertEquals(GapicServiceConfig.EMPTY_TIMEOUT, retrySettings.get(retryParamsName).timeout()); 61 assertEquals( 62 GapicServiceConfig.EMPTY_RETRY_POLICY, retrySettings.get(retryParamsName).retryPolicy()); 63 assertEquals(GapicRetrySettings.Kind.NONE, retrySettings.get(retryParamsName).kind()); 64 65 Map<String, List<Code>> retryCodes = serviceConfig.getAllRetryCodes(service); 66 assertEquals(1, retryCodes.size()); 67 assertEquals( 68 "no_retry_codes", serviceConfig.getRetryCodeName(service, service.methods().get(0))); 69 assertEquals(GapicServiceConfig.EMPTY_RETRY_CODES, retryCodes.get("no_retry_codes")); 70 } 71 72 @Test serviceConfig_basic()73 public void serviceConfig_basic() { 74 FileDescriptor echoFileDescriptor = EchoOuterClass.getDescriptor(); 75 Service service = parseService(echoFileDescriptor); 76 77 String jsonFilename = "showcase_grpc_service_config.json"; 78 Path jsonPath = Paths.get(TESTDATA_DIRECTORY, jsonFilename); 79 Optional<GapicServiceConfig> serviceConfigOpt = ServiceConfigParser.parse(jsonPath.toString()); 80 assertTrue(serviceConfigOpt.isPresent()); 81 GapicServiceConfig serviceConfig = serviceConfigOpt.get(); 82 83 Map<String, GapicRetrySettings> retrySettings = serviceConfig.getAllGapicRetrySettings(service); 84 assertEquals(2, retrySettings.size()); 85 Map<String, List<Code>> retryCodes = serviceConfig.getAllRetryCodes(service); 86 assertEquals(2, retryCodes.size()); 87 88 // Echo method has an explicitly-defined setting. 89 Method method = findMethod(service, "Echo"); 90 assertThat(method).isNotNull(); 91 String retryParamsName = serviceConfig.getRetryParamsName(service, method); 92 assertEquals("retry_policy_1_params", retryParamsName); 93 GapicRetrySettings settings = retrySettings.get(retryParamsName); 94 assertThat(settings).isNotNull(); 95 assertEquals(10, settings.timeout().getSeconds()); 96 assertEquals(GapicRetrySettings.Kind.FULL, settings.kind()); 97 98 MethodConfig.RetryPolicy retryPolicy = settings.retryPolicy(); 99 assertEquals(3, retryPolicy.getMaxAttempts()); 100 assertEquals(100, Durations.toMillis(retryPolicy.getInitialBackoff())); 101 assertEquals(3000, Durations.toMillis(retryPolicy.getMaxBackoff())); 102 assertEquals(2.0, retryPolicy.getBackoffMultiplier(), EPSILON); 103 104 String retryCodeName = serviceConfig.getRetryCodeName(service, method); 105 assertEquals("retry_policy_1_codes", retryCodeName); 106 List<Code> retryCode = retryCodes.get(retryCodeName); 107 assertThat(retryCode).containsExactly(Code.UNAVAILABLE, Code.UNKNOWN); 108 109 // Chat method defaults to the service-defined setting. 110 method = findMethod(service, "Chat"); 111 assertThat(method).isNotNull(); 112 retryParamsName = serviceConfig.getRetryParamsName(service, method); 113 assertEquals("no_retry_0_params", retryParamsName); 114 115 settings = retrySettings.get(retryParamsName); 116 assertThat(settings).isNotNull(); 117 assertEquals(5, settings.timeout().getSeconds()); 118 assertEquals(GapicServiceConfig.EMPTY_RETRY_POLICY, settings.retryPolicy()); 119 assertEquals(GapicRetrySettings.Kind.NO_RETRY, settings.kind()); 120 121 retryCodeName = serviceConfig.getRetryCodeName(service, method); 122 assertEquals("no_retry_0_codes", retryCodeName); 123 assertEquals(GapicServiceConfig.EMPTY_RETRY_CODES, retryCodes.get(retryCodeName)); 124 } 125 126 @Test serviceConfig_withBatchingSettings()127 public void serviceConfig_withBatchingSettings() { 128 FileDescriptor echoFileDescriptor = EchoOuterClass.getDescriptor(); 129 Service service = parseService(echoFileDescriptor); 130 131 String jsonFilename = "showcase_grpc_service_config.json"; 132 Path jsonPath = Paths.get(TESTDATA_DIRECTORY, jsonFilename); 133 134 GapicBatchingSettings origBatchingSetting = 135 GapicBatchingSettings.builder() 136 .setProtoPakkage("google.showcase.v1beta1") 137 .setServiceName("Echo") 138 .setMethodName("Echo") 139 .setElementCountThreshold(1000) 140 .setRequestByteThreshold(2000) 141 .setDelayThresholdMillis(3000) 142 .setBatchedFieldName("name") 143 .setDiscriminatorFieldNames(Arrays.asList("severity")) 144 .build(); 145 Optional<List<GapicBatchingSettings>> batchingSettingsOpt = 146 Optional.of(Arrays.asList(origBatchingSetting)); 147 148 Optional<GapicServiceConfig> serviceConfigOpt = ServiceConfigParser.parse(jsonPath.toString()); 149 assertTrue(serviceConfigOpt.isPresent()); 150 GapicServiceConfig serviceConfig = serviceConfigOpt.get(); 151 serviceConfig.setBatchingSettings(batchingSettingsOpt); 152 153 Map<String, GapicRetrySettings> retrySettings = serviceConfig.getAllGapicRetrySettings(service); 154 assertEquals(2, retrySettings.size()); 155 Map<String, List<Code>> retryCodes = serviceConfig.getAllRetryCodes(service); 156 assertEquals(2, retryCodes.size()); 157 158 // Echo method has an explicitly-defined setting. 159 Method method = findMethod(service, "Echo"); 160 assertThat(method).isNotNull(); 161 162 // No change to the retry settings. 163 String retryParamsName = serviceConfig.getRetryParamsName(service, method); 164 assertEquals("retry_policy_1_params", retryParamsName); 165 GapicRetrySettings settings = retrySettings.get(retryParamsName); 166 assertThat(settings).isNotNull(); 167 assertEquals(10, settings.timeout().getSeconds()); 168 assertEquals(GapicRetrySettings.Kind.FULL, settings.kind()); 169 170 // No changge to the retry codes. 171 String retryCodeName = serviceConfig.getRetryCodeName(service, method); 172 assertEquals("retry_policy_1_codes", retryCodeName); 173 List<Code> retryCode = retryCodes.get(retryCodeName); 174 assertThat(retryCode).containsExactly(Code.UNAVAILABLE, Code.UNKNOWN); 175 176 // Check batching settings. 177 assertTrue(serviceConfig.hasBatchingSetting(service, method)); 178 Optional<GapicBatchingSettings> batchingSettingOpt = 179 serviceConfig.getBatchingSetting(service, method); 180 assertTrue(batchingSettingOpt.isPresent()); 181 GapicBatchingSettings batchingSetting = batchingSettingOpt.get(); 182 assertEquals( 183 origBatchingSetting.elementCountThreshold(), batchingSetting.elementCountThreshold()); 184 assertEquals( 185 origBatchingSetting.requestByteThreshold(), batchingSetting.requestByteThreshold()); 186 assertEquals( 187 origBatchingSetting.delayThresholdMillis(), batchingSetting.delayThresholdMillis()); 188 189 // Chat method defaults to the service-defined setting. 190 method = findMethod(service, "Chat"); 191 assertThat(method).isNotNull(); 192 retryParamsName = serviceConfig.getRetryParamsName(service, method); 193 assertEquals("no_retry_0_params", retryParamsName); 194 retryCodeName = serviceConfig.getRetryCodeName(service, method); 195 assertEquals("no_retry_0_codes", retryCodeName); 196 assertFalse(serviceConfig.hasBatchingSetting(service, method)); 197 } 198 199 @Test serviceConfig_withLroRetrySettings()200 public void serviceConfig_withLroRetrySettings() { 201 FileDescriptor echoFileDescriptor = EchoOuterClass.getDescriptor(); 202 Service service = parseService(echoFileDescriptor); 203 204 String jsonFilename = "showcase_grpc_service_config.json"; 205 Path jsonPath = Paths.get(TESTDATA_DIRECTORY, jsonFilename); 206 207 // Construct LRO retry settings. 208 GapicLroRetrySettings origLroRetrySetting = 209 GapicLroRetrySettings.builder() 210 .setProtoPakkage("google.showcase.v1beta1") 211 .setServiceName("Echo") 212 .setMethodName("Echo") 213 .setInitialPollDelayMillis(100) 214 .setPollDelayMultiplier(1.5) 215 .setMaxPollDelayMillis(200) 216 .setTotalPollTimeoutMillis(300) 217 .build(); 218 Optional<List<GapicLroRetrySettings>> lroRetrySettingsOpt = 219 Optional.of(Arrays.asList(origLroRetrySetting)); 220 221 Optional<GapicServiceConfig> serviceConfigOpt = ServiceConfigParser.parse(jsonPath.toString()); 222 assertTrue(serviceConfigOpt.isPresent()); 223 GapicServiceConfig serviceConfig = serviceConfigOpt.get(); 224 serviceConfig.setLroRetrySettings(lroRetrySettingsOpt); 225 226 // Check LRO retry settings. 227 Method method = findMethod(service, "Echo"); 228 assertTrue(serviceConfig.hasLroRetrySetting(service, method)); 229 Optional<GapicLroRetrySettings> retrievedSettingsOpt = 230 serviceConfig.getLroRetrySetting(service, method); 231 assertTrue(retrievedSettingsOpt.isPresent()); 232 GapicLroRetrySettings retrievedSettings = retrievedSettingsOpt.get(); 233 assertEquals( 234 origLroRetrySetting.initialPollDelayMillis(), retrievedSettings.initialPollDelayMillis()); 235 assertEquals(origLroRetrySetting.maxPollDelayMillis(), retrievedSettings.maxPollDelayMillis()); 236 assertEquals( 237 origLroRetrySetting.totalPollTimeoutMillis(), retrievedSettings.totalPollTimeoutMillis()); 238 } 239 parseService(FileDescriptor fileDescriptor)240 private static Service parseService(FileDescriptor fileDescriptor) { 241 Map<String, Message> messageTypes = Parser.parseMessages(fileDescriptor); 242 Map<String, ResourceName> resourceNames = Parser.parseResourceNames(fileDescriptor); 243 Set<ResourceName> outputResourceNames = new HashSet<>(); 244 List<Service> services = 245 Parser.parseService( 246 fileDescriptor, messageTypes, resourceNames, Optional.empty(), outputResourceNames); 247 assertEquals(1, services.size()); 248 249 return services.get(0); 250 } 251 findMethod(Service service, String methodName)252 private static Method findMethod(Service service, String methodName) { 253 for (Method m : service.methods()) { 254 if (m.name().equals(methodName)) { 255 return m; 256 } 257 } 258 return null; 259 } 260 } 261