/** * *************************************************************************** * Copyright (c) 2010 Qcadoo Limited * Project: Qcadoo Framework * Version: 1.4 * * This file is part of Qcadoo. * * Qcadoo is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation; either version 3 of the License, * or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * *************************************************************************** */ package com.qcadoo.plugin.internal.aop; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import com.qcadoo.plugin.api.PluginStateResolver; import com.qcadoo.plugin.api.RunIfEnabled; import com.qcadoo.plugin.internal.PluginUtilsService; public class RunIfEnabledTest { private static final String PLUGIN_NAME = "somePlugin"; private static final String SECOND_PLUGIN_NAME = "someSecondPlugin"; @Mock private DependencyMock dependencyMock; private static AspectDependencyMock aspectDependencyMock; private PluginStateResolver pluginStateResolver; private interface DependencyMock { void run(); } private interface AspectDependencyMock { void runBefore(); void runAround(); void runAfter(); } private static class MethodLevelAnnotatedClass { private DependencyMock dependencyMock; public MethodLevelAnnotatedClass(final DependencyMock dependencyMock) { this.dependencyMock = dependencyMock; } @RunIfEnabled(PLUGIN_NAME) public void run() { dependencyMock.run(); } } @RunIfEnabled(PLUGIN_NAME) private static class ClassLevelAnnotatedClass { private DependencyMock dependencyMock; public ClassLevelAnnotatedClass(final DependencyMock dependencyMock) { this.dependencyMock = dependencyMock; } public void run() { dependencyMock.run(); } } @RunIfEnabled({ PLUGIN_NAME, SECOND_PLUGIN_NAME }) private static class ClassLevelAnnotatedWithManyPlugins { private DependencyMock dependencyMock; public ClassLevelAnnotatedWithManyPlugins(final DependencyMock dependencyMock) { this.dependencyMock = dependencyMock; } public void run() { dependencyMock.run(); } } private static class MethodLevelAnnotatedWithManyPlugins { private DependencyMock dependencyMock; public MethodLevelAnnotatedWithManyPlugins(final DependencyMock dependencyMock) { this.dependencyMock = dependencyMock; } @RunIfEnabled({ PLUGIN_NAME, SECOND_PLUGIN_NAME }) public void run() { dependencyMock.run(); } } @RunIfEnabled({ PLUGIN_NAME }) private static class MethodAndClassLevelAnnotated { private DependencyMock dependencyMock; public MethodAndClassLevelAnnotated(final DependencyMock dependencyMock) { this.dependencyMock = dependencyMock; } @RunIfEnabled({ SECOND_PLUGIN_NAME }) public void run() { dependencyMock.run(); } } private static class ClassWithoutAnnotations { private DependencyMock dependencyMock; public ClassWithoutAnnotations(final DependencyMock dependencyMock) { this.dependencyMock = dependencyMock; } public void runFirst() { dependencyMock.run(); } public void runSecond() { dependencyMock.run(); } public void runThird(final Object arg) { dependencyMock.run(); } public void runFourth() { dependencyMock.run(); } } private static class ClassWithRegularMethodExpectingPjpArgument { @RunIfEnabled(PLUGIN_NAME) public void doSthg(final ProceedingJoinPoint pjp) throws Throwable { pjp.proceed(); } @RunIfEnabled(PLUGIN_NAME) public void doSthgWithManyArgs(final ProceedingJoinPoint pjp, final Object secondArg) throws Throwable { pjp.proceed(); } } @SuppressWarnings("deprecation") @Before public final void init() { MockitoAnnotations.initMocks(this); pluginStateResolver = mock(PluginStateResolver.class); PluginUtilsService pluginUtilsService = new PluginUtilsService(pluginStateResolver); given(pluginStateResolver.isEnabled(Mockito.anyString())).willReturn(false); given(pluginStateResolver.isEnabledOrEnabling(Mockito.anyString())).willReturn(false); pluginUtilsService.init(); aspectDependencyMock = mock(AspectDependencyMock.class); } @Test public final void shouldNotRunWithMethodLevelAnnotation() { // given MethodLevelAnnotatedClass object = new MethodLevelAnnotatedClass(dependencyMock); // when object.run(); // then verify(pluginStateResolver).isEnabled(PLUGIN_NAME); verify(dependencyMock, never()).run(); } @Test public final void shouldRunWithMethodLevelAnnotation() { // given enablePlugin(PLUGIN_NAME); MethodLevelAnnotatedClass object = new MethodLevelAnnotatedClass(dependencyMock); // when object.run(); // then verify(pluginStateResolver).isEnabled(PLUGIN_NAME); verify(dependencyMock).run(); } @Test public final void shouldNotRunWithClassLevelAnnotation() { // given ClassLevelAnnotatedClass object = new ClassLevelAnnotatedClass(dependencyMock); // when object.run(); // then verify(pluginStateResolver).isEnabled(PLUGIN_NAME); verify(dependencyMock, never()).run(); } @Test public final void shouldRunWithClassLevelAnnotation() { // given enablePlugin(PLUGIN_NAME); ClassLevelAnnotatedClass object = new ClassLevelAnnotatedClass(dependencyMock); // when object.run(); // then verify(pluginStateResolver).isEnabled(PLUGIN_NAME); verify(dependencyMock).run(); } @Test public final void shouldRunClassLevelAnnotationWithManyPlugins() { // given enablePlugin(PLUGIN_NAME); enablePlugin(SECOND_PLUGIN_NAME); ClassLevelAnnotatedWithManyPlugins object = new ClassLevelAnnotatedWithManyPlugins(dependencyMock); // when object.run(); // then verify(pluginStateResolver).isEnabled(PLUGIN_NAME); verify(pluginStateResolver).isEnabled(SECOND_PLUGIN_NAME); verify(dependencyMock).run(); } @Test public final void shouldNotRunClassLevelAnnotationWithManyPlugins() { // given enablePlugin(PLUGIN_NAME); ClassLevelAnnotatedWithManyPlugins object = new ClassLevelAnnotatedWithManyPlugins(dependencyMock); // when object.run(); // then verify(pluginStateResolver).isEnabled(PLUGIN_NAME); verify(pluginStateResolver).isEnabled(SECOND_PLUGIN_NAME); verify(dependencyMock, never()).run(); } @Test public final void shouldRunMethodLevelAnnotationWithManyPlugins() { // given enablePlugin(PLUGIN_NAME); enablePlugin(SECOND_PLUGIN_NAME); MethodLevelAnnotatedWithManyPlugins object = new MethodLevelAnnotatedWithManyPlugins(dependencyMock); // when object.run(); // then verify(pluginStateResolver).isEnabled(PLUGIN_NAME); verify(pluginStateResolver).isEnabled(SECOND_PLUGIN_NAME); verify(dependencyMock).run(); } @Test public final void shouldNotRunMethodLevelAnnotationWithManyPlugins() { // given enablePlugin(PLUGIN_NAME); MethodLevelAnnotatedWithManyPlugins object = new MethodLevelAnnotatedWithManyPlugins(dependencyMock); // when object.run(); // then verify(pluginStateResolver).isEnabled(PLUGIN_NAME); verify(pluginStateResolver).isEnabled(SECOND_PLUGIN_NAME); verify(dependencyMock, never()).run(); } @Test public final void shouldRunAndIgnoreClassLevelAnnotationIfMethodIsAlsoAnnotated() { // given enablePlugin(SECOND_PLUGIN_NAME); MethodAndClassLevelAnnotated object = new MethodAndClassLevelAnnotated(dependencyMock); // when object.run(); // then verify(pluginStateResolver, never()).isEnabled(PLUGIN_NAME); verify(pluginStateResolver).isEnabled(SECOND_PLUGIN_NAME); verify(dependencyMock).run(); } @Test public final void shouldNotRunAndIgnoreClassLevelAnnotationIfMethodIsAlsoAnnotated() { // given enablePlugin(PLUGIN_NAME); MethodAndClassLevelAnnotated object = new MethodAndClassLevelAnnotated(dependencyMock); // when object.run(); // then verify(pluginStateResolver, never()).isEnabled(PLUGIN_NAME); verify(pluginStateResolver).isEnabled(SECOND_PLUGIN_NAME); verify(dependencyMock, never()).run(); } @Test public final void shouldRunAnnotatedMethodWithPjpAsArgument() throws Throwable { // given enablePlugin(PLUGIN_NAME); final ProceedingJoinPoint pjpMock = mock(ProceedingJoinPoint.class); final ClassWithRegularMethodExpectingPjpArgument object = new ClassWithRegularMethodExpectingPjpArgument(); // when object.doSthg(pjpMock); // then verify(pjpMock).proceed(); } @Test public final void shouldNotRunAnnotatedMethodWithPjpAsArgument() throws Throwable { // given final ProceedingJoinPoint pjpMock = mock(ProceedingJoinPoint.class); final ClassWithRegularMethodExpectingPjpArgument object = new ClassWithRegularMethodExpectingPjpArgument(); // when object.doSthg(pjpMock); // then verify(pjpMock, never()).proceed(); } @Test public final void shouldRunAnnotatedMethodWithPjpAsFirstOfManyArgument() throws Throwable { // given enablePlugin(PLUGIN_NAME); final ProceedingJoinPoint pjpMock = mock(ProceedingJoinPoint.class); final ClassWithRegularMethodExpectingPjpArgument object = new ClassWithRegularMethodExpectingPjpArgument(); // when object.doSthgWithManyArgs(pjpMock, "some arbitrary second arg"); // then verify(pjpMock).proceed(); } @Test public final void shouldNotRunAnnotatedMethodWithPjpAsFirstOfManyArgument() throws Throwable { // given final ProceedingJoinPoint pjpMock = mock(ProceedingJoinPoint.class); final ClassWithRegularMethodExpectingPjpArgument object = new ClassWithRegularMethodExpectingPjpArgument(); // when object.doSthgWithManyArgs(pjpMock, "some arbitrary second arg"); // then verify(pjpMock, never()).proceed(); } @Test public final void shouldRunAnnotatedAroundAdviceButPerformJoinPointExecution() { // given enablePlugin(PLUGIN_NAME); ClassWithoutAnnotations object = new ClassWithoutAnnotations(dependencyMock); // when object.runFirst(); // then verify(dependencyMock).run(); verify(aspectDependencyMock).runBefore(); verify(aspectDependencyMock).runAround(); verify(aspectDependencyMock).runAfter(); } @Test public final void shouldNotRunAnnotatedAroundAdviceButPerformJoinPointExecution() { // given ClassWithoutAnnotations object = new ClassWithoutAnnotations(dependencyMock); // when object.runFirst(); // then verify(dependencyMock).run(); verify(aspectDependencyMock, never()).runBefore(); verify(aspectDependencyMock, never()).runAround(); verify(aspectDependencyMock, never()).runAfter(); } @Test public final void shouldRunAnnotatedAroundAdviceWithManyArgumentsButPerformJoinPointExecution() { // given enablePlugin(PLUGIN_NAME); ClassWithoutAnnotations object = new ClassWithoutAnnotations(dependencyMock); // when object.runThird("someArg"); // then verify(dependencyMock).run(); verify(aspectDependencyMock).runAround(); } @Test public final void shouldNotRunAnnotatedAroundAdviceWithManyArgumentsButPerformJoinPointExecution() { // given ClassWithoutAnnotations object = new ClassWithoutAnnotations(dependencyMock); // when object.runThird("someArg"); // then verify(dependencyMock).run(); verify(aspectDependencyMock, never()).runAround(); } @Test public final void shouldRunAspectAnnotatedAroundAdviceButPerformJoinPointExecution() { // given enablePlugin(PLUGIN_NAME); ClassWithoutAnnotations object = new ClassWithoutAnnotations(dependencyMock); // when object.runSecond(); // then verify(dependencyMock).run(); verify(aspectDependencyMock).runBefore(); verify(aspectDependencyMock).runAround(); verify(aspectDependencyMock).runAfter(); } @Test public final void shouldNotRunAspectAnnotatedAroundAdviceButPerformJoinPointExecution() { // given ClassWithoutAnnotations object = new ClassWithoutAnnotations(dependencyMock); // when object.runSecond(); // then verify(dependencyMock).run(); verify(aspectDependencyMock, never()).runBefore(); verify(aspectDependencyMock, never()).runAround(); verify(aspectDependencyMock, never()).runAfter(); } @Test public final void shouldRunAspectAnnotatedAroundAdviceButNotPerformJoinPointExecution() { // given enablePlugin(PLUGIN_NAME); ClassWithoutAnnotations object = new ClassWithoutAnnotations(dependencyMock); // when object.runFourth(); // then verify(dependencyMock, never()).run(); verify(aspectDependencyMock).runAround(); } @Test public final void shouldNotRunAspectAnnotatedAroundAdviceButPerformJoinPointExecutionEvenIfAdviceBodyDoseNotPerformThem() { // given ClassWithoutAnnotations object = new ClassWithoutAnnotations(dependencyMock); // when object.runFourth(); // then verify(dependencyMock).run(); verify(aspectDependencyMock, never()).runAround(); } @Aspect public static final class AspectWithMethodLevelAnnotation { @RunIfEnabled(PLUGIN_NAME) @org.aspectj.lang.annotation.Before("execution(* ClassWithoutAnnotations.runFirst())") public void before() { aspectDependencyMock.runBefore(); } @RunIfEnabled(PLUGIN_NAME) @Around("execution(* ClassWithoutAnnotations.runFirst())") public void around(final ProceedingJoinPoint pjp) throws Throwable { aspectDependencyMock.runAround(); pjp.proceed(); } @RunIfEnabled(PLUGIN_NAME) @After("execution(* ClassWithoutAnnotations.runFirst())") public void after() { aspectDependencyMock.runAfter(); } } @Aspect @RunIfEnabled(PLUGIN_NAME) public static final class AspectWithClassLevelAnnotation { @org.aspectj.lang.annotation.Before("execution(* ClassWithoutAnnotations.runSecond())") public void before() { aspectDependencyMock.runBefore(); } @Around("execution(* ClassWithoutAnnotations.runSecond())") public void around(final ProceedingJoinPoint pjp) throws Throwable { aspectDependencyMock.runAround(); pjp.proceed(); } @Around("execution(* ClassWithoutAnnotations.runThird(..)) && args(someArg)") public void aroundWithManyArgs(final ProceedingJoinPoint pjp, final Object someArg) throws Throwable { aspectDependencyMock.runAround(); pjp.proceed(); } @Around("execution(* ClassWithoutAnnotations.runFourth())") public void aroundWithoutPjpProceedInBody(final ProceedingJoinPoint pjp) throws Throwable { aspectDependencyMock.runAround(); } @After("execution(* ClassWithoutAnnotations.runSecond())") public void after() { aspectDependencyMock.runAfter(); } } @SuppressWarnings("deprecation") private void enablePlugin(final String pluginName) { given(pluginStateResolver.isEnabled(pluginName)).willReturn(true); given(pluginStateResolver.isEnabledOrEnabling(pluginName)).willReturn(true); } }