/*
* Copyright 2014, Simon Matić Langford
*
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.betfair.cougar.core.impl.ev;
import com.betfair.cougar.api.ExecutionContext;
import com.betfair.cougar.api.RequestUUID;
import com.betfair.cougar.api.geolocation.GeoLocationDetails;
import com.betfair.cougar.api.security.IdentityChain;
import com.betfair.cougar.core.api.ServiceVersion;
import com.betfair.cougar.core.api.ev.ExecutionObserver;
import com.betfair.cougar.core.api.ev.ExecutionVenue;
import com.betfair.cougar.core.api.ev.OperationKey;
import com.betfair.cougar.core.api.ev.TimeConstraints;
import com.betfair.cougar.core.api.tracing.Tracer;
import com.betfair.cougar.core.impl.security.IdentityChainImpl;
import com.betfair.cougar.core.impl.tracing.TracingEndObserver;
import com.betfair.cougar.util.RequestUUIDImpl;
import com.betfair.cougar.util.UUIDGeneratorImpl;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.internal.matchers.Equals;
import org.mockito.internal.matchers.Same;
import java.util.Date;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
/**
*
*/
public class InProcessExecutableTest {
@BeforeClass
public static void setupUuid()
{
RequestUUIDImpl.setGenerator(new UUIDGeneratorImpl());
}
@Test
public void subCall()
{
Tracer tracer = mock(Tracer.class);
InProcessExecutable victim = new InProcessExecutable(tracer);
ExecutionContext ctx = mock(ExecutionContext.class);
OperationKey expectedOp = new OperationKey(new ServiceVersion(1,0),"Wibble","wobble");
OperationKey op = new OperationKey(expectedOp, "_IN_PROCESS");
Object[] args = new Object[1];
ExecutionObserver obs = mock(ExecutionObserver.class);
ExecutionVenue venue = mock(ExecutionVenue.class);
TimeConstraints constraints = mock(TimeConstraints.class);
RequestUUID parentUuid = new RequestUUIDImpl();
when(ctx.getRequestUUID()).thenReturn(parentUuid);
when(ctx.isTransportSecure()).thenReturn(false);
IdentityChain mockIdentityChain = new IdentityChainImpl();
when(ctx.getIdentity()).thenReturn(mockIdentityChain);
GeoLocationDetails mockLocation = mock(GeoLocationDetails.class);
when(ctx.getLocation()).thenReturn(mockLocation);
when(ctx.getReceivedTime()).thenReturn(new Date(0L));
when(ctx.getRequestTime()).thenReturn(new Date(0L));
when(ctx.getTransportSecurityStrengthFactor()).thenReturn(0);
victim.execute(ctx, op, args, obs, venue, constraints);
ArgumentCaptor<ExecutionContext> arg1 = ArgumentCaptor.forClass(ExecutionContext.class);
ArgumentCaptor<OperationKey> arg2 = ArgumentCaptor.forClass(OperationKey.class);
ArgumentCaptor<Object[]> arg3 = ArgumentCaptor.forClass(Object[].class);
ArgumentCaptor<ExecutionObserver> arg4 = ArgumentCaptor.forClass(ExecutionObserver.class);
ArgumentCaptor<TimeConstraints> arg5 = ArgumentCaptor.forClass(TimeConstraints.class);
// moved from this as it was failing and v hard to work out which bit was failing
// verify(venue, times(1)).execute(argThat(isSubContextOf(ctx)),eq(new OperationKey(op, null)),same(args),
// argThat(isTracingEndObserver(obs, parentUuid, op, tracer)),same(constraints));
verify(venue, times(1)).execute(arg1.capture(), arg2.capture(), arg3.capture(), arg4.capture(), arg5.capture());
assertThat(arg1.getValue(), isSubContextOf(ctx));
assertThat(arg2.getValue(), new Equals(expectedOp));
assertThat(arg3.getValue(), new Same(args));
assertThat(arg4.getValue(), isTracingEndObserver(obs, parentUuid, expectedOp, tracer));
assertThat(arg5.getValue(), new Same(constraints));
}
private static boolean isSubUuidOf(RequestUUID subUuid, RequestUUID parentUuid, StringBuilder buffer) {
if (parentUuid.getRootUUIDComponent()==null && !subUuid.getRootUUIDComponent().equals(parentUuid.getLocalUUIDComponent())) {
buffer.append("Sub uuid isn't rooted at parent");
return false;
}
if (!subUuid.getParentUUIDComponent().equals(parentUuid.getLocalUUIDComponent())) {
buffer.append("Sub uuid doesn't have correct parent");
return false;
}
if (subUuid.getLocalUUIDComponent().equals(parentUuid.getLocalUUIDComponent())) {
buffer.append("Sub uuid local component is same as parent");
return false;
}
return true;
}
private Matcher<ExecutionObserver> isTracingEndObserver(final ExecutionObserver child, final RequestUUID parentUuid, final OperationKey key, final Tracer tracer) {
return new BaseMatcher<ExecutionObserver>() {
@Override
public boolean matches(Object o) {
if (!(o instanceof TracingEndObserver)) {
return false;
}
TracingEndObserver tracingObserver = (TracingEndObserver) o;
if (tracingObserver.getObs() != child) {
return false;
}
if (tracingObserver.getParentUuid() != parentUuid) {
return false;
}
if (!tracingObserver.getKey().equals(key)) {
return false;
}
if (tracingObserver.getTracer() != tracer) {
return false;
}
if (!isSubUuidOf(tracingObserver.getCallUuid(), parentUuid, new StringBuilder())) {
return false;
}
return true;
}
@Override
public void describeTo(Description description) {
description.appendText("isTracingEndObserver()");
}
};
}
private Matcher<ExecutionContext> isSubContextOf(final ExecutionContext ctx) {
return new BaseMatcher<ExecutionContext>() {
StringBuilder buffer = new StringBuilder();
@Override
public boolean matches(Object o) {
if (!(o instanceof ExecutionContext)) {
buffer.append("Not an ExecutionContext!");
return false;
}
ExecutionContext subCandidate = (ExecutionContext) o;
if (subCandidate.traceLoggingEnabled() != ctx.traceLoggingEnabled()) {
buffer.append("Trace logging not " + ctx.traceLoggingEnabled());
return false;
}
if (!subCandidate.getLocation().equals(ctx.getLocation())) {
buffer.append("Location not " + ctx.getLocation());
return false;
}
if (!subCandidate.isTransportSecure()) {
buffer.append("Transport not secure");
return false;
}
if (!subCandidate.getIdentity().equals(ctx.getIdentity())) {
buffer.append("Identity not "+ctx.getIdentity());
return false;
}
if (subCandidate.getTransportSecurityStrengthFactor() != Integer.MAX_VALUE) {
buffer.append("Transport strength not " + Integer.MAX_VALUE);
return false;
}
if (!subCandidate.getReceivedTime().equals(subCandidate.getRequestTime())) {
buffer.append("Received time not request time");
return false;
}
if (subCandidate.getReceivedTime().compareTo(ctx.getReceivedTime()) <= 0) {
buffer.append("Received time before or same as " + ctx.getReceivedTime());
return false;
}
RequestUUID subUuid = subCandidate.getRequestUUID();
RequestUUID parentUuid = ctx.getRequestUUID();
if (!isSubUuidOf(subUuid, parentUuid, buffer)) {
return false;
}
return true;
}
@Override
public void describeTo(Description description) {
description.appendText("isSubContextOf("+ctx+"): "+buffer.toString());
}
};
}
}