package profiler.org.sagebionetworks.usagemetrics;

import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.CALLS_REAL_METHODS;
import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.lang.reflect.Method;

import org.apache.commons.logging.Log;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.reflect.MethodSignature;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.sagebionetworks.repo.web.controller.ActivityLoggerTestHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:activityLogger-spb.xml" })
public class ActivityLoggerTest {

	private static Method SIMPLE_METHOD = null;
	private static Method ANNOTATION_METHOD = null;

	private static final String SIMPLE_METHOD_NAME = "testMethod";
	private static final String ANNOTATION_METHOD_NAME = "testAnnotationsMethod";

	private static final String[]  SIMPLE_METHOD_PARAM_NAMES = {"arg1", "arg2"};
	private static final String[]  ANNOTATION_METHOD_PARAM_NAMES = {"id", "userId"};

	private static final Class<?>[] SIMPLE_METHOD_ARG_TYPES = new Class<?>[] {String.class, Integer.class};
	private static final Class<?>[] ANNOTATION_METHOD_ARG_TYPES = new Class<?>[] {String.class, String.class};

	private static final Object[] SIMPLE_METHOD_ARGS = new Object[] {"testarg", new Integer(12)};
	private static final Object[] ANNOTATION_METHOD_ARGS = new Object[] {"entityIdval", "userIdval"};

	private static final String ARG_FMT_STRING = "%s=%s&%s=%s";

	private static final String SIMPLE_ARG_STRING = String.format(
			ARG_FMT_STRING, SIMPLE_METHOD_PARAM_NAMES[0],
			SIMPLE_METHOD_ARGS[0], SIMPLE_METHOD_PARAM_NAMES[1],
			SIMPLE_METHOD_ARGS[1]);

	private static final String ANNOTATION_ARG_STRING = String.format(
			ARG_FMT_STRING, ANNOTATION_METHOD_PARAM_NAMES[0],
			ANNOTATION_METHOD_ARGS[0], ANNOTATION_METHOD_PARAM_NAMES[1],
			ANNOTATION_METHOD_ARGS[1]);

	@Autowired
	ActivityLogger activityLogger;

	private static Log mockLog;

	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
		Class<ActivityLoggerTestHelper> clazz = ActivityLoggerTestHelper.class;
		Method[] declaredMethods = clazz.getDeclaredMethods();
		for (Method method : declaredMethods) {
			if (method.getName().equalsIgnoreCase(SIMPLE_METHOD_NAME)) {
				SIMPLE_METHOD = method;
			}
			if (method.getName().equalsIgnoreCase(ANNOTATION_METHOD_NAME)) {
				ANNOTATION_METHOD = method;
			}
		}
	}

	@Before
	public void before() throws Exception {
		mockLog = mock(Log.class);
		ActivityLogger.setLog(mockLog);
	}

	@Test
	public void testDoBasicLogging() throws Throwable {
		ProceedingJoinPoint mockPjp = mock(ProceedingJoinPoint.class);
		MethodSignature mockSig = mock(MethodSignature.class, RETURNS_DEEP_STUBS);

		when(mockPjp.getArgs()).thenReturn(ANNOTATION_METHOD_ARGS);
		when(mockPjp.getSignature()).thenReturn(mockSig);

		when(mockSig.getDeclaringType()).thenReturn(ActivityLoggerTestHelper.class);
		when(mockSig.getMethod()).thenReturn(ANNOTATION_METHOD);
		when(mockSig.getName()).thenReturn(ANNOTATION_METHOD_NAME);
		when(mockSig.getParameterNames()).thenReturn(ANNOTATION_METHOD_PARAM_NAMES);

		activityLogger.doBasicLogging(mockPjp);

		ArgumentCaptor<String> arg = ArgumentCaptor.forClass(String.class);
		verify(mockLog).trace(arg.capture());

		String[] methodAndArgs = arg.getValue().split("\\?");
		String[] classAndMethod = methodAndArgs[0].split("/");

		String latencyArg = "latency=0&";
		int indexOf = methodAndArgs[1].indexOf(latencyArg);

		assertEquals(ANNOTATION_ARG_STRING, methodAndArgs[1].substring(indexOf + latencyArg.length()));

		assertEquals(ActivityLoggerTestHelper.class.getSimpleName(), classAndMethod[0]);
		assertEquals(classAndMethod[1], ANNOTATION_METHOD_NAME);
	}

	@Test
	public void testDoBasicLoggingJoinPointNotMethod() throws Throwable {
		ProceedingJoinPoint mockPjp = mock(ProceedingJoinPoint.class);
		Signature mockSig = mock(Signature.class, CALLS_REAL_METHODS);

		when(mockPjp.getSignature()).thenReturn(mockSig);

		activityLogger.doBasicLogging(mockPjp);

		verify(mockLog).error(anyString());
	}
}

@@ -715,16 +715,121 @@
 Captor;%0A
+import org.sagebionetworks.logging.SynapseEvent;%0Aimport org.sagebionetworks.logging.SynapseLoggingUtils;%0A
 import o
@@ -3355,28 +3355,8 @@
 lass
-, RETURNS_DEEP_STUBS
 );%0A%0A
@@ -3916,443 +3916,322 @@
 ring
-%5B%5D methodAndArgs = arg.getValue().split(%22%5C%5C?%22);%0A%09%09String%5B%5D classAndMethod = methodAndArgs%5B0%5D.split(%22/%22);%0A%0A%09%09String latencyArg = %22latency=0&%22;%0A%09%09int indexOf = methodAndArgs%5B1%5D.indexOf(latencyArg);%0A%0A%09%09assertEquals(ANNOTATION_ARG_STRING, methodAndArgs%5B1%5D.substring(indexOf + latencyArg.length()));%0A%0A%09%09assertEquals(ActivityLoggerTestHelper.class.getSimpleName(), classAndMethod%5B0%5D);%0A%09%09assertEquals(classAndMethod%5B1%5D, ANNOTATION_METHOD_NAME
+ val = String.format(%222012-08-11 00:00:00,000 %5BTRACE%5D - %25s%22, arg.getValue());%0A%09%09SynapseEvent synapseEvent = SynapseLoggingUtils.parseSynapseEvent(val);%0A%0A%09%09assertEquals(ActivityLoggerTestHelper.class.getSimpleName(), synapseEvent.getController());%0A%09%09assertEquals(ANNOTATION_METHOD_NAME, synapseEvent.getMethodName()
 );%0A%09

Change ActivityLoggerTest to use SynapseLoggingUtils methods