/** * Copyright 2016 Netflix, Inc. * <p/> * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * <p/> * http://www.apache.org/licenses/LICENSE-2.0 * <p/> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.netflix.hystrix.serial; import com.netflix.hystrix.ExecutionResult; import com.netflix.hystrix.HystrixCollapserKey; import com.netflix.hystrix.HystrixCommandGroupKey; import com.netflix.hystrix.HystrixCommandKey; import com.netflix.hystrix.HystrixCommandMetrics; import com.netflix.hystrix.HystrixCommandProperties; import com.netflix.hystrix.HystrixEventType; import com.netflix.hystrix.HystrixInvokableInfo; import com.netflix.hystrix.HystrixThreadPoolKey; import com.netflix.hystrix.metric.HystrixRequestEvents; import org.junit.Test; import java.io.IOException; import java.util.ArrayList; import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; public class SerialHystrixRequestEventsTest { private static final HystrixCommandGroupKey groupKey = HystrixCommandGroupKey.Factory.asKey("GROUP"); private static final HystrixThreadPoolKey threadPoolKey = HystrixThreadPoolKey.Factory.asKey("ThreadPool"); private static final HystrixCommandKey fooKey = HystrixCommandKey.Factory.asKey("Foo"); private static final HystrixCommandKey barKey = HystrixCommandKey.Factory.asKey("Bar"); private static final HystrixCollapserKey collapserKey = HystrixCollapserKey.Factory.asKey("FooCollapser"); @Test public void testEmpty() throws IOException { HystrixRequestEvents request = new HystrixRequestEvents(new ArrayList<HystrixInvokableInfo<?>>()); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[]", actual); } @Test public void testSingleSuccess() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); executions.add(new SimpleExecution(fooKey, 100, HystrixEventType.SUCCESS)); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[{\"name\":\"Foo\",\"events\":[\"SUCCESS\"],\"latencies\":[100]}]", actual); } @Test public void testSingleFailureFallbackMissing() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); executions.add(new SimpleExecution(fooKey, 101, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_MISSING)); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[{\"name\":\"Foo\",\"events\":[\"FAILURE\",\"FALLBACK_MISSING\"],\"latencies\":[101]}]", actual); } @Test public void testSingleFailureFallbackSuccess() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); executions.add(new SimpleExecution(fooKey, 102, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_SUCCESS)); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[{\"name\":\"Foo\",\"events\":[\"FAILURE\",\"FALLBACK_SUCCESS\"],\"latencies\":[102]}]", actual); } @Test public void testSingleFailureFallbackRejected() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); executions.add(new SimpleExecution(fooKey, 103, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_REJECTION)); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[{\"name\":\"Foo\",\"events\":[\"FAILURE\",\"FALLBACK_REJECTION\"],\"latencies\":[103]}]", actual); } @Test public void testSingleFailureFallbackFailure() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); executions.add(new SimpleExecution(fooKey, 104, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_FAILURE)); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[{\"name\":\"Foo\",\"events\":[\"FAILURE\",\"FALLBACK_FAILURE\"],\"latencies\":[104]}]", actual); } @Test public void testSingleTimeoutFallbackSuccess() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); executions.add(new SimpleExecution(fooKey, 105, HystrixEventType.TIMEOUT, HystrixEventType.FALLBACK_SUCCESS)); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[{\"name\":\"Foo\",\"events\":[\"TIMEOUT\",\"FALLBACK_SUCCESS\"],\"latencies\":[105]}]", actual); } @Test public void testSingleSemaphoreRejectedFallbackSuccess() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); executions.add(new SimpleExecution(fooKey, 1, HystrixEventType.SEMAPHORE_REJECTED, HystrixEventType.FALLBACK_SUCCESS)); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[{\"name\":\"Foo\",\"events\":[\"SEMAPHORE_REJECTED\",\"FALLBACK_SUCCESS\"],\"latencies\":[1]}]", actual); } @Test public void testSingleThreadPoolRejectedFallbackSuccess() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); executions.add(new SimpleExecution(fooKey, 1, HystrixEventType.THREAD_POOL_REJECTED, HystrixEventType.FALLBACK_SUCCESS)); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[{\"name\":\"Foo\",\"events\":[\"THREAD_POOL_REJECTED\",\"FALLBACK_SUCCESS\"],\"latencies\":[1]}]", actual); } @Test public void testSingleShortCircuitedFallbackSuccess() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); executions.add(new SimpleExecution(fooKey, 1, HystrixEventType.SHORT_CIRCUITED, HystrixEventType.FALLBACK_SUCCESS)); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[{\"name\":\"Foo\",\"events\":[\"SHORT_CIRCUITED\",\"FALLBACK_SUCCESS\"],\"latencies\":[1]}]", actual); } @Test public void testSingleBadRequest() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); executions.add(new SimpleExecution(fooKey, 50, HystrixEventType.BAD_REQUEST)); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[{\"name\":\"Foo\",\"events\":[\"BAD_REQUEST\"],\"latencies\":[50]}]", actual); } @Test public void testTwoSuccessesSameKey() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); HystrixInvokableInfo<Integer> foo1 = new SimpleExecution(fooKey, 23, HystrixEventType.SUCCESS); HystrixInvokableInfo<Integer> foo2 = new SimpleExecution(fooKey, 34, HystrixEventType.SUCCESS); executions.add(foo1); executions.add(foo2); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[{\"name\":\"Foo\",\"events\":[\"SUCCESS\"],\"latencies\":[23,34]}]", actual); } @Test public void testTwoSuccessesDifferentKey() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); HystrixInvokableInfo<Integer> foo1 = new SimpleExecution(fooKey, 23, HystrixEventType.SUCCESS); HystrixInvokableInfo<Integer> bar1 = new SimpleExecution(barKey, 34, HystrixEventType.SUCCESS); executions.add(foo1); executions.add(bar1); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertTrue(actual.equals("[{\"name\":\"Foo\",\"events\":[\"SUCCESS\"],\"latencies\":[23]},{\"name\":\"Bar\",\"events\":[\"SUCCESS\"],\"latencies\":[34]}]") || actual.equals("[{\"name\":\"Bar\",\"events\":[\"SUCCESS\"],\"latencies\":[34]},{\"name\":\"Foo\",\"events\":[\"SUCCESS\"],\"latencies\":[23]}]")); } @Test public void testTwoFailuresSameKey() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); HystrixInvokableInfo<Integer> foo1 = new SimpleExecution(fooKey, 56, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_SUCCESS); HystrixInvokableInfo<Integer> foo2 = new SimpleExecution(fooKey, 67, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_SUCCESS); executions.add(foo1); executions.add(foo2); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[{\"name\":\"Foo\",\"events\":[\"FAILURE\",\"FALLBACK_SUCCESS\"],\"latencies\":[56,67]}]", actual); } @Test public void testTwoSuccessesOneFailureSameKey() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); HystrixInvokableInfo<Integer> foo1 = new SimpleExecution(fooKey, 10, HystrixEventType.SUCCESS); HystrixInvokableInfo<Integer> foo2 = new SimpleExecution(fooKey, 67, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_SUCCESS); HystrixInvokableInfo<Integer> foo3 = new SimpleExecution(fooKey, 11, HystrixEventType.SUCCESS); executions.add(foo1); executions.add(foo2); executions.add(foo3); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertTrue(actual.equals("[{\"name\":\"Foo\",\"events\":[\"SUCCESS\"],\"latencies\":[10,11]},{\"name\":\"Foo\",\"events\":[\"FAILURE\",\"FALLBACK_SUCCESS\"],\"latencies\":[67]}]") || actual.equals("[{\"name\":\"Foo\",\"events\":[\"FAILURE\",\"FALLBACK_SUCCESS\"],\"latencies\":[67]},{\"name\":\"Foo\",\"events\":[\"SUCCESS\"],\"latencies\":[10,11]}]")); } @Test public void testSingleResponseFromCache() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); HystrixInvokableInfo<Integer> foo1 = new SimpleExecution(fooKey, 23, "cacheKeyA", HystrixEventType.SUCCESS); HystrixInvokableInfo<Integer> cachedFoo1 = new SimpleExecution(fooKey, "cacheKeyA"); executions.add(foo1); executions.add(cachedFoo1); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[{\"name\":\"Foo\",\"events\":[\"SUCCESS\"],\"latencies\":[23],\"cached\":1}]", actual); } @Test public void testMultipleResponsesFromCache() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); HystrixInvokableInfo<Integer> foo1 = new SimpleExecution(fooKey, 23, "cacheKeyA", HystrixEventType.SUCCESS); HystrixInvokableInfo<Integer> cachedFoo1 = new SimpleExecution(fooKey, "cacheKeyA"); HystrixInvokableInfo<Integer> anotherCachedFoo1 = new SimpleExecution(fooKey, "cacheKeyA"); executions.add(foo1); executions.add(cachedFoo1); executions.add(anotherCachedFoo1); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[{\"name\":\"Foo\",\"events\":[\"SUCCESS\"],\"latencies\":[23],\"cached\":2}]", actual); } @Test public void testMultipleCacheKeys() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); HystrixInvokableInfo<Integer> foo1 = new SimpleExecution(fooKey, 23, "cacheKeyA", HystrixEventType.SUCCESS); HystrixInvokableInfo<Integer> cachedFoo1 = new SimpleExecution(fooKey, "cacheKeyA"); HystrixInvokableInfo<Integer> foo2 = new SimpleExecution(fooKey, 67, "cacheKeyB", HystrixEventType.SUCCESS); HystrixInvokableInfo<Integer> cachedFoo2 = new SimpleExecution(fooKey, "cacheKeyB"); executions.add(foo1); executions.add(cachedFoo1); executions.add(foo2); executions.add(cachedFoo2); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertTrue(actual.equals("[{\"name\":\"Foo\",\"events\":[\"SUCCESS\"],\"latencies\":[67],\"cached\":1},{\"name\":\"Foo\",\"events\":[\"SUCCESS\"],\"latencies\":[23],\"cached\":1}]") || actual.equals("[{\"name\":\"Foo\",\"events\":[\"SUCCESS\"],\"latencies\":[23],\"cached\":1},{\"name\":\"Foo\",\"events\":[\"SUCCESS\"],\"latencies\":[67],\"cached\":1}]")); } @Test public void testSingleSuccessMultipleEmits() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); executions.add(new SimpleExecution(fooKey, 100, HystrixEventType.EMIT, HystrixEventType.EMIT, HystrixEventType.EMIT, HystrixEventType.SUCCESS)); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[{\"name\":\"Foo\",\"events\":[{\"name\":\"EMIT\",\"count\":3},\"SUCCESS\"],\"latencies\":[100]}]", actual); } @Test public void testSingleSuccessMultipleEmitsAndFallbackEmits() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); executions.add(new SimpleExecution(fooKey, 100, HystrixEventType.EMIT, HystrixEventType.EMIT, HystrixEventType.EMIT, HystrixEventType.FAILURE, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_EMIT, HystrixEventType.FALLBACK_SUCCESS)); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[{\"name\":\"Foo\",\"events\":[{\"name\":\"EMIT\",\"count\":3},\"FAILURE\",{\"name\":\"FALLBACK_EMIT\",\"count\":2},\"FALLBACK_SUCCESS\"],\"latencies\":[100]}]", actual); } @Test public void testCollapsedBatchOfOne() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); executions.add(new SimpleExecution(fooKey, 53, collapserKey, 1, HystrixEventType.SUCCESS)); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[{\"name\":\"Foo\",\"events\":[\"SUCCESS\"],\"latencies\":[53],\"collapsed\":{\"name\":\"FooCollapser\",\"count\":1}}]", actual); } @Test public void testCollapsedBatchOfSix() throws IOException { List<HystrixInvokableInfo<?>> executions = new ArrayList<HystrixInvokableInfo<?>>(); executions.add(new SimpleExecution(fooKey, 53, collapserKey, 6, HystrixEventType.SUCCESS)); HystrixRequestEvents request = new HystrixRequestEvents(executions); String actual = SerialHystrixRequestEvents.toJsonString(request); assertEquals("[{\"name\":\"Foo\",\"events\":[\"SUCCESS\"],\"latencies\":[53],\"collapsed\":{\"name\":\"FooCollapser\",\"count\":6}}]", actual); } private class SimpleExecution implements HystrixInvokableInfo<Integer> { private final HystrixCommandKey commandKey; private final ExecutionResult executionResult; private final String cacheKey; private final HystrixCollapserKey collapserKey; public SimpleExecution(HystrixCommandKey commandKey, int latency, HystrixEventType... events) { this.commandKey = commandKey; this.executionResult = ExecutionResult.from(events).setExecutionLatency(latency); this.cacheKey = null; this.collapserKey = null; } public SimpleExecution(HystrixCommandKey commandKey, int latency, String cacheKey, HystrixEventType... events) { this.commandKey = commandKey; this.executionResult = ExecutionResult.from(events).setExecutionLatency(latency); this.cacheKey = cacheKey; this.collapserKey = null; } public SimpleExecution(HystrixCommandKey commandKey, String cacheKey) { this.commandKey = commandKey; this.executionResult = ExecutionResult.from(HystrixEventType.RESPONSE_FROM_CACHE); this.cacheKey = cacheKey; this.collapserKey = null; } public SimpleExecution(HystrixCommandKey commandKey, int latency, HystrixCollapserKey collapserKey, int batchSize, HystrixEventType... events) { this.commandKey = commandKey; ExecutionResult interimResult = ExecutionResult.from(events).setExecutionLatency(latency); for (int i = 0; i < batchSize; i++) { interimResult = interimResult.addEvent(HystrixEventType.COLLAPSED); } this.executionResult = interimResult; this.cacheKey = null; this.collapserKey = collapserKey; } @Override public HystrixCommandGroupKey getCommandGroup() { return groupKey; } @Override public HystrixCommandKey getCommandKey() { return commandKey; } @Override public HystrixThreadPoolKey getThreadPoolKey() { return threadPoolKey; } @Override public String getPublicCacheKey() { return cacheKey; } @Override public HystrixCollapserKey getOriginatingCollapserKey() { return collapserKey; } @Override public HystrixCommandMetrics getMetrics() { return null; } @Override public HystrixCommandProperties getProperties() { return null; } @Override public boolean isCircuitBreakerOpen() { return false; } @Override public boolean isExecutionComplete() { return true; } @Override public boolean isExecutedInThread() { return false; //do i want this? } @Override public boolean isSuccessfulExecution() { return executionResult.getEventCounts().contains(HystrixEventType.SUCCESS); } @Override public boolean isFailedExecution() { return executionResult.getEventCounts().contains(HystrixEventType.FAILURE); } @Override public Throwable getFailedExecutionException() { return null; } @Override public boolean isResponseFromFallback() { return executionResult.getEventCounts().contains(HystrixEventType.FALLBACK_SUCCESS); } @Override public boolean isResponseTimedOut() { return executionResult.getEventCounts().contains(HystrixEventType.TIMEOUT); } @Override public boolean isResponseShortCircuited() { return executionResult.getEventCounts().contains(HystrixEventType.SHORT_CIRCUITED); } @Override public boolean isResponseFromCache() { return executionResult.getEventCounts().contains(HystrixEventType.RESPONSE_FROM_CACHE); } @Override public boolean isResponseRejected() { return executionResult.isResponseRejected(); } @Override public boolean isResponseSemaphoreRejected() { return executionResult.getEventCounts().contains(HystrixEventType.SEMAPHORE_REJECTED); } @Override public boolean isResponseThreadPoolRejected() { return executionResult.getEventCounts().contains(HystrixEventType.THREAD_POOL_REJECTED); } @Override public List<HystrixEventType> getExecutionEvents() { return executionResult.getOrderedList(); } @Override public int getNumberEmissions() { return executionResult.getEventCounts().getCount(HystrixEventType.EMIT); } @Override public int getNumberFallbackEmissions() { return executionResult.getEventCounts().getCount(HystrixEventType.FALLBACK_EMIT); } @Override public int getNumberCollapsed() { return executionResult.getEventCounts().getCount(HystrixEventType.COLLAPSED); } @Override public int getExecutionTimeInMilliseconds() { return executionResult.getExecutionLatency(); } @Override public long getCommandRunStartTimeInNanos() { return System.currentTimeMillis(); } @Override public ExecutionResult.EventCounts getEventCounts() { return executionResult.getEventCounts(); } @Override public String toString() { return "SimpleExecution{" + "commandKey=" + commandKey.name() + ", executionResult=" + executionResult + ", cacheKey='" + cacheKey + '\'' + ", collapserKey=" + collapserKey + '}'; } } }