Search in sources :

Example 1 with TimingKey

use of com.linkedin.r2.message.timing.TimingKey in project rest.li by linkedin.

the class TestSslTimingKey method testSslTimingKey.

@Test
public void testSslTimingKey() throws Exception {
    if (isHttp2StreamBasedChannel())
        return;
    final EchoService client = new RestEchoClient(Bootstrap.createURI(_port, Bootstrap.getEchoURI(), true), createClient());
    final String msg = "This is a simple http echo message";
    final FutureCallback<String> callback = new FutureCallback<>();
    client.echo(msg, callback);
    Assert.assertEquals(callback.get(), msg);
    RequestContext context = _clientCaptureFilter.getRequestContext();
    @SuppressWarnings("unchecked") Map<TimingKey, TimingContext> map = (Map<TimingKey, TimingContext>) context.getLocalAttr("timings");
    Assert.assertNotNull(map);
    Assert.assertTrue(map.containsKey(SslHandshakeTimingHandler.TIMING_KEY));
    TimingContext timingContext = map.get(SslHandshakeTimingHandler.TIMING_KEY);
    Assert.assertNotNull(timingContext);
}
Also used : TimingKey(com.linkedin.r2.message.timing.TimingKey) EchoService(com.linkedin.r2.sample.echo.EchoService) RestEchoClient(com.linkedin.r2.sample.echo.rest.RestEchoClient) RequestContext(com.linkedin.r2.message.RequestContext) Map(java.util.Map) FutureCallback(com.linkedin.common.callback.FutureCallback) TimingContext(com.linkedin.r2.message.timing.TimingContextUtil.TimingContext) AbstractEchoServiceTest(test.r2.integ.clientserver.providers.AbstractEchoServiceTest) Test(org.testng.annotations.Test)

Example 2 with TimingKey

use of com.linkedin.r2.message.timing.TimingKey in project rest.li by linkedin.

the class TestLatencyInstrumentation method checkTimingKeyCompleteness.

/**
 * Ensures that the recorded timing keys are "complete", meaning that all keys which are expected to be present
 * are present. Also ensures that no unexpected keys are present.
 * @param forceException parameter from the test method
 * @param timingImportanceThreshold parameter from the test method
 */
private void checkTimingKeyCompleteness(boolean forceException, TimingImportance timingImportanceThreshold, boolean useScatterGather) {
    // Form the set of expected timing keys using the current test parameters
    Set<TimingKey> expectedKeys = Arrays.stream(FrameworkTimingKeys.values()).map(FrameworkTimingKeys::key).filter(timingKey -> !(useScatterGather && timingKey.getName().startsWith(FrameworkTimingKeys.KEY_PREFIX + "client"))).filter(timingKey -> {
        if (forceException) {
            return !TIMING_KEYS_MISSING_ON_ERROR.contains(timingKey);
        } else {
            return !TIMING_KEYS_MISSING_ON_SUCCESS.contains(timingKey);
        }
    }).filter(timingKey -> !TIMING_KEYS_MISSING_ON_PROTOCOL_2_0_0.contains(timingKey)).filter(timingKey -> timingImportanceThreshold == null || TIMING_KEYS_ALWAYS_PRESENT.contains(timingKey) || timingKey.getTimingImportance().isAtLeast(timingImportanceThreshold)).collect(Collectors.toSet());
    // Check that all keys have complete timings (not -1) and that there are no unexpected keys
    for (TimingKey timingKey : _resultMap.keySet()) {
        if (expectedKeys.contains(timingKey)) {
            expectedKeys.remove(timingKey);
            Assert.assertNotEquals(_resultMap.get(timingKey).getDurationNano(), -1, timingKey.getName() + " is -1");
        } else if (timingKey.getName().contains(FrameworkTimingKeys.KEY_PREFIX)) {
            Assert.fail("Encountered unexpected key: " + timingKey);
        }
    }
    // Check that the set of recorded timing keys is "complete"
    Assert.assertTrue(expectedKeys.isEmpty(), "Missing keys: " + expectedKeys.stream().map(key -> String.format("\"%s\"", key.getName())).collect(Collectors.joining(", ")));
}
Also used : LatencyInstrumentationResource(com.linkedin.restli.examples.instrumentation.server.LatencyInstrumentationResource) Arrays(java.util.Arrays) DataProvider(org.testng.annotations.DataProvider) RestLiIntegrationTest(com.linkedin.restli.examples.RestLiIntegrationTest) HashMap(java.util.HashMap) Test(org.testng.annotations.Test) StreamRequest(com.linkedin.r2.message.stream.StreamRequest) AfterMethod(org.testng.annotations.AfterMethod) RestResponse(com.linkedin.r2.message.rest.RestResponse) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) Request(com.linkedin.r2.message.Request) Assert(org.testng.Assert) RequestFinalizer(com.linkedin.r2.util.finalizer.RequestFinalizer) StreamResponse(com.linkedin.r2.message.stream.StreamResponse) ResponseFuture(com.linkedin.restli.client.ResponseFuture) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) Map(java.util.Map) RestLiResponseException(com.linkedin.restli.client.RestLiResponseException) RequestContextUtil(com.linkedin.r2.util.RequestContextUtil) FilterChain(com.linkedin.r2.filter.FilterChain) FrameworkTimingKeys(com.linkedin.r2.message.timing.FrameworkTimingKeys) IdEntityResponse(com.linkedin.restli.common.IdEntityResponse) RestRequest(com.linkedin.r2.message.rest.RestRequest) SingleRetry(com.linkedin.test.util.retry.SingleRetry) StreamFilter(com.linkedin.r2.filter.message.stream.StreamFilter) FilterChains(com.linkedin.r2.filter.FilterChains) LatencyInstrumentationBuilders(com.linkedin.restli.examples.instrumentation.client.LatencyInstrumentationBuilders) Response(com.linkedin.r2.message.Response) RemoteInvocationException(com.linkedin.r2.RemoteInvocationException) Collection(java.util.Collection) BeforeMethod(org.testng.annotations.BeforeMethod) Set(java.util.Set) InstrumentationControl(com.linkedin.restli.examples.instrumentation.api.InstrumentationControl) TimingKey(com.linkedin.r2.message.timing.TimingKey) RequestFinalizerManager(com.linkedin.r2.util.finalizer.RequestFinalizerManager) Collectors(java.util.stream.Collectors) TimeUnit(java.util.concurrent.TimeUnit) CountDownLatch(java.util.concurrent.CountDownLatch) List(java.util.List) NextFilter(com.linkedin.r2.filter.NextFilter) RequestContext(com.linkedin.r2.message.RequestContext) CreateIdEntityRequest(com.linkedin.restli.client.CreateIdEntityRequest) RestFilter(com.linkedin.r2.filter.message.rest.RestFilter) TimingContextUtil(com.linkedin.r2.message.timing.TimingContextUtil) TimingImportance(com.linkedin.r2.message.timing.TimingImportance) Collections(java.util.Collections) TimingKey(com.linkedin.r2.message.timing.TimingKey)

Example 3 with TimingKey

use of com.linkedin.r2.message.timing.TimingKey in project rest.li by linkedin.

the class TestTimingCallback method testOrdering.

/**
 * Ensures that timing keys are marked in the same order that they are added.
 */
@Test
public void testOrdering() {
    final RequestContext requestContext = new RequestContext();
    final Callback<Long> callback = new Callback<Long>() {

        @Override
        public void onSuccess(Long result) {
            Map<TimingKey, TimingContextUtil.TimingContext> timings = TimingContextUtil.getTimingsMap(requestContext);
            // Ensure all keys are present
            Assert.assertTrue(timings.containsKey(KEY_H));
            Assert.assertTrue(timings.containsKey(KEY_M));
            Assert.assertTrue(timings.containsKey(KEY_L));
            // Ensure timing start times/durations are consistent based on their ordering in the callback
            TimingContextUtil.TimingContext contextH = timings.get(KEY_H);
            TimingContextUtil.TimingContext contextM = timings.get(KEY_M);
            TimingContextUtil.TimingContext contextL = timings.get(KEY_L);
            Assert.assertTrue(contextM.getStartTimeNano() < contextL.getStartTimeNano());
            Assert.assertTrue(contextL.getStartTimeNano() < contextH.getStartTimeNano());
            Assert.assertTrue(contextL.getDurationNano() < contextM.getDurationNano());
            Assert.assertTrue(contextH.getDurationNano() < contextM.getDurationNano());
        }

        @Override
        public void onError(Throwable e) {
        }
    };
    final Callback<Long> timingCallback = new TimingCallback.Builder<>(callback, requestContext).addBeginTimingKey(KEY_M).addBeginTimingKey(KEY_L).addEndTimingKey(KEY_L).addBeginTimingKey(KEY_H).addEndTimingKey(KEY_H).addEndTimingKey(KEY_M).build();
    timingCallback.onSuccess(1L);
}
Also used : Callback(com.linkedin.common.callback.Callback) RequestContext(com.linkedin.r2.message.RequestContext) Test(org.testng.annotations.Test)

Example 4 with TimingKey

use of com.linkedin.r2.message.timing.TimingKey in project rest.li by linkedin.

the class TestTimingCallback method testBuilder.

/**
 * Ensures that the builder can correctly determine how to filter out timing keys based on the current timing
 * importance threshold, and that it can correctly determine when to return the original callback rather than wrapping
 * it with a new one.
 * @param timingImportanceThreshold timing importance threshold
 */
@Test(dataProvider = "timingImportanceThreshold")
public void testBuilder(TimingImportance timingImportanceThreshold) {
    final RequestContext requestContext = new RequestContext();
    if (timingImportanceThreshold != null) {
        requestContext.putLocalAttr(TimingContextUtil.TIMING_IMPORTANCE_THRESHOLD_KEY_NAME, timingImportanceThreshold);
    }
    final Callback<Long> callback = new Callback<Long>() {

        @Override
        public void onSuccess(Long result) {
            Map<TimingKey, TimingContextUtil.TimingContext> timings = TimingContextUtil.getTimingsMap(requestContext);
            // Ensure that keys have been filtered out correctly
            if (timingImportanceThreshold == null || TimingImportance.LOW.isAtLeast(timingImportanceThreshold)) {
                Assert.assertTrue(timings.containsKey(KEY_L));
                Assert.assertTrue(timings.containsKey(KEY_M));
            } else if (TimingImportance.MEDIUM.isAtLeast(timingImportanceThreshold)) {
                Assert.assertFalse(timings.containsKey(KEY_L));
                Assert.assertTrue(timings.containsKey(KEY_M));
            } else {
                Assert.assertFalse(timings.containsKey(KEY_L));
                Assert.assertFalse(timings.containsKey(KEY_M));
            }
        }

        @Override
        public void onError(Throwable e) {
        }
    };
    final Callback<Long> timingCallback = new TimingCallback.Builder<>(callback, requestContext).addBeginTimingKey(KEY_L).addBeginTimingKey(KEY_M).addEndTimingKey(KEY_L).addEndTimingKey(KEY_M).build();
    // Ensure that the builder can correctly determine when to return the original callback
    if (timingImportanceThreshold == null || !timingImportanceThreshold.equals(TimingImportance.HIGH)) {
        Assert.assertTrue(timingCallback instanceof TimingCallback);
    } else {
        Assert.assertFalse(timingCallback instanceof TimingCallback);
    }
    timingCallback.onSuccess(1L);
}
Also used : Callback(com.linkedin.common.callback.Callback) RequestContext(com.linkedin.r2.message.RequestContext) Test(org.testng.annotations.Test)

Example 5 with TimingKey

use of com.linkedin.r2.message.timing.TimingKey in project rest.li by linkedin.

the class LatencyInstrumentationResource method create.

/**
 * This is the "upstream endpoint" which is queried directly by the integration test.
 * This endpoint makes a call to {@link #batchPartialUpdate(BatchPatchRequest)} (the "downstream endpoint"),
 * then packs all the client-side timing data into the original server-side request context.
 */
@ReturnEntity
@RestMethod.Create
public CreateKVResponse<Long, InstrumentationControl> create(InstrumentationControl control) {
    final boolean forceException = control.isForceException();
    final boolean useScatterGather = control.isUseScatterGather();
    final String uriPrefix = control.getServiceUriPrefix();
    // Build the downstream request
    final BatchPartialUpdateEntityRequestBuilder<Long, InstrumentationControl> builder = new LatencyInstrumentationBuilders().batchPartialUpdateAndGet();
    final PatchRequest<InstrumentationControl> patch = PatchGenerator.diffEmpty(control);
    for (long i = 0; i < DOWNSTREAM_BATCH_SIZE; i++) {
        builder.input(i, patch);
    }
    final BatchPartialUpdateEntityRequest<Long, InstrumentationControl> request = builder.build();
    // Set up the Rest.li client config
    final RestLiClientConfig clientConfig = new RestLiClientConfig();
    clientConfig.setUseStreaming(control.isUseStreaming());
    if (useScatterGather) {
        clientConfig.setScatterGatherStrategy(new DefaultScatterGatherStrategy(new DummyUriMapper()));
    }
    final TransportClient transportClient = new HttpClientFactory.Builder().build().getClient(Collections.emptyMap());
    final RestClient restClient = new ForceScatterGatherRestClient(new TransportClientAdapter(transportClient), uriPrefix, clientConfig);
    final RequestContext serverRequestContext = getContext().getRawRequestContext();
    final RequestContext clientRequestContext = new RequestContext();
    // Load the timing importance threshold from the server context into the client context
    clientRequestContext.putLocalAttr(TimingContextUtil.TIMING_IMPORTANCE_THRESHOLD_KEY_NAME, serverRequestContext.getLocalAttr(TimingContextUtil.TIMING_IMPORTANCE_THRESHOLD_KEY_NAME));
    try {
        // Make the request, then assert that the returned errors (if any) are as expected
        BatchKVResponse<Long, UpdateEntityStatus<InstrumentationControl>> response = restClient.sendRequest(request, clientRequestContext).getResponseEntity();
        final Map<Long, ErrorResponse> errors = response.getErrors();
        if (forceException && errors.isEmpty()) {
            throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Expected failures for the downstream batch request, but found none.");
        }
        if (!forceException && !errors.isEmpty()) {
            throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Expected no failures for the downstream batch request, but found some.");
        }
        for (ErrorResponse errorResponse : errors.values()) {
            if (!DOWNSTREAM_ERROR_CODE.equals(errorResponse.getCode())) {
                throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Encountered a downstream failure with an unexpected or missing error code.");
            }
        }
    } catch (RemoteInvocationException e) {
        throw new RestLiServiceException(HttpStatus.S_500_INTERNAL_SERVER_ERROR, "Downstream failures should be batch entry failures, but encountered a top-level request failure.", e);
    }
    Map<TimingKey, TimingContextUtil.TimingContext> clientTimingsMap = TimingContextUtil.getTimingsMap(clientRequestContext);
    Map<TimingKey, TimingContextUtil.TimingContext> serverTimingsMap = TimingContextUtil.getTimingsMap(serverRequestContext);
    // Load all client timings into the server timings map
    serverTimingsMap.putAll(clientTimingsMap);
    getContext().setResponseHeader(HAS_CLIENT_TIMINGS_HEADER, Boolean.TRUE.toString());
    if (forceException) {
        throw new RestLiServiceException(HttpStatus.S_400_BAD_REQUEST, "You wanted me to fail, so I failed.").setCode(UPSTREAM_ERROR_CODE);
    }
    return new CreateKVResponse<>(1L, control);
}
Also used : RestLiClientConfig(com.linkedin.restli.client.util.RestLiClientConfig) BatchPartialUpdateEntityRequestBuilder(com.linkedin.restli.client.BatchPartialUpdateEntityRequestBuilder) InstrumentationControl(com.linkedin.restli.examples.instrumentation.api.InstrumentationControl) DefaultScatterGatherStrategy(com.linkedin.restli.client.DefaultScatterGatherStrategy) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) TimingKey(com.linkedin.r2.message.timing.TimingKey) TransportClientAdapter(com.linkedin.r2.transport.common.bridge.client.TransportClientAdapter) RequestContext(com.linkedin.r2.message.RequestContext) RemoteInvocationException(com.linkedin.r2.RemoteInvocationException) UpdateEntityStatus(com.linkedin.restli.common.UpdateEntityStatus) TransportClient(com.linkedin.r2.transport.common.bridge.client.TransportClient) RestClient(com.linkedin.restli.client.RestClient) LatencyInstrumentationBuilders(com.linkedin.restli.examples.instrumentation.client.LatencyInstrumentationBuilders) ErrorResponse(com.linkedin.restli.common.ErrorResponse) CreateKVResponse(com.linkedin.restli.server.CreateKVResponse) ReturnEntity(com.linkedin.restli.server.annotations.ReturnEntity)

Aggregations

RequestContext (com.linkedin.r2.message.RequestContext)5 TimingKey (com.linkedin.r2.message.timing.TimingKey)4 Test (org.testng.annotations.Test)4 Callback (com.linkedin.common.callback.Callback)2 RemoteInvocationException (com.linkedin.r2.RemoteInvocationException)2 TimingContextUtil (com.linkedin.r2.message.timing.TimingContextUtil)2 InstrumentationControl (com.linkedin.restli.examples.instrumentation.api.InstrumentationControl)2 LatencyInstrumentationBuilders (com.linkedin.restli.examples.instrumentation.client.LatencyInstrumentationBuilders)2 RestLiServiceException (com.linkedin.restli.server.RestLiServiceException)2 ArrayList (java.util.ArrayList)2 Map (java.util.Map)2 FutureCallback (com.linkedin.common.callback.FutureCallback)1 FilterChain (com.linkedin.r2.filter.FilterChain)1 FilterChains (com.linkedin.r2.filter.FilterChains)1 NextFilter (com.linkedin.r2.filter.NextFilter)1 RestFilter (com.linkedin.r2.filter.message.rest.RestFilter)1 StreamFilter (com.linkedin.r2.filter.message.stream.StreamFilter)1 Request (com.linkedin.r2.message.Request)1 Response (com.linkedin.r2.message.Response)1 RestRequest (com.linkedin.r2.message.rest.RestRequest)1